Index: /branches/czw_branch/20110406/Ohana/Makefile.in
===================================================================
--- /branches/czw_branch/20110406/Ohana/Makefile.in	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/Makefile.in	(revision 31606)
@@ -76,39 +76,39 @@
 	mkdir -p $(DESTLIB)
 	mkdir -p $(DESTBIN)
-	for i in $(LIBS); do make $$i.install || exit 1; done
+	for i in $(LIBS); do $(MAKE) $$i.install || exit 1; done
 	chmod +x ohana-config
 	cp -f ohana-config $(DESTBIN)/
 
 bins: 
-	for i in $(PROGRAM); do make $$i; done
+	for i in $(PROGRAM); do $(MAKE) $$i; done
 
 all:
-	make libs || exit 1
-	for i in $(PROGRAM); do make $$i || exit 1; done
+	$(MAKE) libs || exit 1
+	for i in $(PROGRAM); do $(MAKE) $$i || exit 1; done
 
 extras:
-	for i in $(EXTRAS); do make $$i || exit 1; done
+	for i in $(EXTRAS); do $(MAKE) $$i || exit 1; done
 
 pantasks:
-	make libs || exit 1
-	cd src/opihi; make pclient.install && exit 1
-	cd src/opihi; make pcontrol.install && exit 1
-	cd src/opihi; make pantasks.install && exit 1
+	$(MAKE) libs || exit 1
+	cd src/opihi; $(MAKE) pclient.install && exit 1
+	cd src/opihi; $(MAKE) pcontrol.install && exit 1
+	cd src/opihi; $(MAKE) pantasks.install && exit 1
 
 mana:
-	make libs
-	make kapa2.install
-	cd src/opihi; make mana.install && exit 1
+	$(MAKE) libs
+	$(MAKE) kapa2.install
+	cd src/opihi; $(MAKE) mana.install && exit 1
 
 dvoshell:
-	make libs
-	make kapa2.install
-	cd src/opihi; make dvo.install && exit 1
+	$(MAKE) libs
+	$(MAKE) kapa2.install
+	cd src/opihi; $(MAKE) dvo.install && exit 1
 
 clean:
 	@if [ "$(ARCH)" = "" ]; then echo ""; echo " *** please define ARCH ***"; echo; exit 1; fi
-	for i in $(LIBS); do make $$i.clean || exit 1; done
-	for i in $(PROGRAM); do make $$i.clean || exit 1; done
-	for i in $(EXTRAS); do make $$i.clean || exit 1; done
+	for i in $(LIBS); do $(MAKE) $$i.clean || exit 1; done
+	for i in $(PROGRAM); do $(MAKE) $$i.clean || exit 1; done
+	for i in $(EXTRAS); do $(MAKE) $$i.clean || exit 1; done
 	@rm -f `find . -name .mana`
 	@rm -f `find . -name .dvo`
@@ -117,16 +117,16 @@
 dist:
 	@if [ "$(ARCH)" = "" ]; then echo ""; echo " *** please define ARCH ***"; echo; exit 1; fi
-	for i in $(LIBS); do make $$i.dist || exit 1; done
-	for i in $(PROGRAM); do make $$i.dist || exit 1; done
+	for i in $(LIBS); do $(MAKE) $$i.dist || exit 1; done
+	for i in $(PROGRAM); do $(MAKE) $$i.dist || exit 1; done
 	@echo -n -e "\0033]0; *** Ohana: done $@ *** \0007" \
 
 install:
 	@if [ "$(ARCH)" = "" ]; then echo ""; echo " *** please define ARCH ***"; echo; exit 1; fi
-	for i in $(LIBS); do make $$i.install || exit 1; done
-	for i in $(PROGRAM); do make $$i.install || exit 1; done
+	for i in $(LIBS); do $(MAKE) $$i.install || exit 1; done
+	for i in $(PROGRAM); do $(MAKE) $$i.install || exit 1; done
 	@echo -n -e "\0033]0; *** Ohana: done $@ *** \0007" \
 
 install.extras:
-	for i in $(EXTRAS); do make $$i.install || exit 1; done
+	for i in $(EXTRAS); do $(MAKE) $$i.install || exit 1; done
 	@echo -n -e "\0033]0; *** Ohana: done $@ *** \0007" \
 
@@ -135,5 +135,5 @@
 	@if [ -d "src/$@" ]; then \
 	  echo -n -e "\0033]0; *** Ohana: $@ *** \0007"; \
-	  (cd src/$@ && make); \
+	  (cd src/$@ && $(MAKE)); \
 	fi
 	@echo -n -e "\0033]0; *** Ohana: done $@ *** \0007" \
@@ -142,9 +142,9 @@
 	@echo -n -e "\0033]0; *** Ohana: $@ *** \0007" \
 	mkdir -p bin/$(ARCH)
-	if [ -d "src/$*" ]; then (cd src/$* && make install); fi
+	if [ -d "src/$*" ]; then (cd src/$* && $(MAKE) install); fi
 
 %.clean:
-	if [ -d "src/$*" ]; then (cd src/$* && make clean); fi
+	if [ -d "src/$*" ]; then (cd src/$* && $(MAKE) clean); fi
 
 %.dist:
-	(cd src/$* && make dist)
+	(cd src/$* && $(MAKE) dist)
Index: /branches/czw_branch/20110406/Ohana/src/addstar/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/addstar/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/addstar/Makefile	(revision 31606)
@@ -267,6 +267,6 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(INSTALL); do make $$i.install || exit; done
+	for i in $(INSTALL); do $(MAKE) $$i.install || exit; done
Index: /branches/czw_branch/20110406/Ohana/src/dvomerge/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/dvomerge/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/dvomerge/Makefile	(revision 31606)
@@ -108,6 +108,6 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(INSTALL); do make $$i.install || exit; done
+	for i in $(INSTALL); do $(MAKE) $$i.install || exit; done
Index: /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 31606)
@@ -202,5 +202,5 @@
     if (newID == 0) {
       fprintf (stderr, "cannot find image ID "OFF_T_FMT"\n",  oldID);
-      exit (2);
+      // exit (2);
     }
     catalog[0].measure[i].imageID = newID;
Index: /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvoverify.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/dvomerge/src/dvoverify.c	(revision 31606)
@@ -148,5 +148,5 @@
 int VerifyTableFile (char *filename) {
 
-  int status;
+  int status, Next;
   off_t Nbytes;
   Header header;
@@ -205,4 +205,5 @@
   // scan all extentions
   Nbytes = 0;
+  Next = -1;
   if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
   while (Nbytes < fileStats.st_size) {
@@ -210,5 +211,9 @@
     // Check on the PHU
     if (!gfits_fread_header (file, &header)) {
-      fprintf (stderr, "unable to read PHU header for %s\n", filename);
+      if (Next == -1) {
+	fprintf (stderr, "unable to read PHU header for %s\n", filename);
+      } else {
+	fprintf (stderr, "unable to read header for %s, extension %d (or file has excess bytes)\n", filename, Next);
+      }
       fclose(file);
       return (FALSE);
@@ -243,4 +248,5 @@
       }
     }
+    Next ++;
   }
   if (DEBUG) fprintf (stderr, "file is good: %s\n", filename);
Index: /branches/czw_branch/20110406/Ohana/src/dvosplit/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/dvosplit/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/dvosplit/Makefile	(revision 31606)
@@ -43,6 +43,6 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(INSTALL); do make $$i.install || exit; done
+	for i in $(INSTALL); do $(MAKE) $$i.install || exit; done
Index: /branches/czw_branch/20110406/Ohana/src/imregister/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/imregister/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/imregister/Makefile	(revision 31606)
@@ -185,9 +185,9 @@
 %.rebuild :
 	rm -f $(BIN)/$*.$(ARCH)
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(INSTALL); do make $$i.install || exit; done
+	for i in $(INSTALL); do $(MAKE) $$i.install || exit; done
Index: /branches/czw_branch/20110406/Ohana/src/kapa2/src/DrawObjects.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/kapa2/src/DrawObjects.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/kapa2/src/DrawObjects.c	(revision 31606)
@@ -1,12 +1,17 @@
 # include "Ximage.h"
 
-# define DrawLine(X1,Y1,X2,Y2) (XDrawLine (graphic->display, graphic->window, graphic->gc, (int)(X1+0.5), (int)(Y1+0.5), (int)(X2+0.5), (int)(Y2+0.5)))
-# define DrawRectangle(X1,Y1,X2,Y2) (XDrawRectangle (graphic->display, graphic->window, graphic->gc, (int)(X1+0.5), (int)(Y1+0.5), (int)(X2+0.5), (int)(Y2+0.5)))
-# define FillRectangle(X1,Y1,X2,Y2) (XFillRectangle (graphic->display, graphic->window, graphic->gc, (int)(X1+0.5), (int)(Y1+0.5), (int)(X2+0.5), (int)(Y2+0.5)))
-# define DrawCircle(X,Y,R) (XDrawArc (graphic->display, graphic->window, graphic->gc, (int)(X-R+0.5), (int)(Y-R+0.5), abs(2*R+0.5), abs(2*R+0.5), 0, 23040))
+# define DrawLine(X1,Y1,X2,Y2) (XDrawLine (graphic->display, graphic->window, graphic->gc, (int)(X1), (int)(Y1), (int)(X2), (int)(Y2)))
+# define DrawRectangle(X1,Y1,X2,Y2) (XDrawRectangle (graphic->display, graphic->window, graphic->gc, (int)(X1), (int)(Y1), (int)(X2), (int)(Y2)))
+# define FillRectangle(X1,Y1,X2,Y2) (XFillRectangle (graphic->display, graphic->window, graphic->gc, (int)(X1), (int)(Y1), (int)(X2), (int)(Y2)))
+# define DrawCircle(X,Y,R) (XDrawArc (graphic->display, graphic->window, graphic->gc, (int)(X-R), (int)(Y-R), abs(2*R), abs(2*R), 0, 23040))
 
 # define CONNECT 0
 # define HISTOGRAM 1
 # define POINTS 2
+
+# define XCENTER 0.0
+# define YCENTER 0.0
+# define CAPSTYLE CapButt
+# define JOINSTYLE JoinMiter
 
 static Graphic *graphic;
@@ -34,22 +39,32 @@
   // this function calls all of the supporting Draw... functions below
   graphic = GetGraphic();
-
-  lweight = MAX (0, MIN (10, object[0].lweight));
+  
+  lweight = MAX (1, MIN (10, object[0].lweight));
+
+  /** some notes on drawing lines in X:
+
+      "In general, drawing a thin line will be faster than drawing a wide line of width
+      one. However, because of their different drawing algorithms, thin lines may not mix
+      well aesthetically with wide lines. If it is desirable to obtain precise and uniform
+      results across all displays, a client should always use a line-width of one rather
+      than a line-width of zero."  -- http://www.hpc.unimelb.edu.au/nec/g1ae02e/chap7.html
+
+  */
 
   /* set line type */
   switch (object[0].ltype) {
     case 0:
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CapNotLast, JoinMiter);
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CAPSTYLE, JOINSTYLE);
       break;
     case 1:
       XSetDashes (graphic->display, graphic->gc, 100, dash, 2);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CapNotLast, JoinMiter);
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
       break;
     case 2:
       XSetDashes (graphic->display, graphic->gc, 10, dot, 2);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CapNotLast, JoinMiter);
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
       break;
     default:
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CapNotLast, JoinMiter);
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CAPSTYLE, JOINSTYLE);
       break;
   }
@@ -76,5 +91,5 @@
   }
 
-  XSetLineAttributes (graphic->display, graphic->gc, 0, LineSolid, CapNotLast, JoinMiter);
+  XSetLineAttributes (graphic->display, graphic->gc, 0, LineSolid, CAPSTYLE, JOINSTYLE);
   XSetForeground (graphic->display, graphic->gc, graphic->fore);
   return (TRUE);
@@ -111,11 +126,11 @@
   for (i = 0; (i < object[0].Npts) && !(finite(x[i]) && finite(y[i])); i++);
   if (i >= object[0].Npts) return;
-  sx0 = x[i]*mxi + y[i]*mxj + bx;
-  sy0 = x[i]*myi + y[i]*myj + by;
+  sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+  sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
 
   for (i++; i < object[0].Npts; i++) {
     if (!(finite(x[i]) && finite(y[i]))) continue;
-    sx1 = x[i]*mxi + y[i]*mxj + bx;
-    sy1 = x[i]*myi + y[i]*myj + by;
+    sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
     
     ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
@@ -213,6 +228,6 @@
 
   /* first valid data point */
-  sx0 = x[i]*mxi + y[i]*mxj + bx;
-  sy0 = x[i]*myi + y[i]*myj + by;
+  sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+  sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
   sx0 = MIN (MAX (sx0, X0), X1);
   sy0 = MAX (MIN (sy0, Y0), Y1);
@@ -223,6 +238,6 @@
 
   /* second valid data point */
-  sx1 = x[i]*mxi + y[i]*mxj + bx;
-  sy1 = x[i]*myi + y[i]*myj + by;
+  sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+  sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
   sx1 = MIN (MAX (sx1, X0), X1);
   sy1 = MAX (MIN (sy1, Y0), Y1);
@@ -246,6 +261,6 @@
   for (i++; i < object[0].Npts; i++) {
     if (!(finite(x[i]) && finite(y[i]))) continue;
-    sx1 = x[i]*mxi + y[i]*mxj + bx;
-    sy1 = x[i]*myi + y[i]*myj + by;
+    sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
     sx1 = MIN (MAX (sx1, X0), X1);
     sy1 = MAX (MIN (sy1, Y0), Y1);
@@ -298,6 +313,6 @@
 
   /* first valid data point */
-  sx0 = x[i]*mxi + y[i]*mxj + bx;
-  sy0 = x[i]*myi + y[i]*myj + by;
+  sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+  sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
   sx0 = MIN (MAX (sx0, X0), X1);
   sy0 = MAX (MIN (sy0, Y0), Y1);
@@ -308,6 +323,6 @@
 
   /* second valid data point */
-  sx1 = x[i]*mxi + y[i]*mxj + bx;
-  sy1 = x[i]*myi + y[i]*myj + by;
+  sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+  sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
   sx1 = MIN (MAX (sx1, X0), X1);
   sy1 = MAX (MIN (sy1, Y0), Y1);
@@ -330,6 +345,6 @@
   for (i++; i < object[0].Npts; i++) {
     if (!(finite(x[i]) && finite(y[i]))) continue;
-    sx1 = x[i]*mxi + y[i]*mxj + bx;
-    sy1 = x[i]*myi + y[i]*myj + by;
+    sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
     sx1 = MIN (MAX (sx1, X0), X1);
     sy1 = MAX (MIN (sy1, Y0), Y1);
@@ -356,5 +371,5 @@
   float *x, *y, *z;
   double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
-  double sx, sy, d, sx1, sy1, sx2, sy2;
+  int sx, sy, sx1, sy1, sx2, sy2, d, D;
   
   mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
@@ -375,13 +390,15 @@
     d = 0.5 * (graphic->dx + graphic->dy) * 0.01;
     x = object[0].x; y = object[0].y; z = object[0].z;
+
     if (object[0].ptype == 0) {	/* filled box */
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  FillRectangle (sx - d*z[i], sy - d*z[i], 2*d*z[i], 2*d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  FillRectangle (sx - D, sy - D, 2*D + 1, 2*D + 1);
 	}
       }
@@ -390,10 +407,11 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawRectangle (sx - d*z[i], sy - d*z[i], 2*d*z[i], 2*d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawRectangle (sx - D, sy - D, 2*D, 2*D);
 	}
       }
@@ -402,11 +420,12 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx - d*z[i], sy, sx + d*z[i] + 1, sy);
-	  DrawLine (sx, sy - d*z[i], sx, sy + d*z[i] + 1);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx - D, sy, sx + D + 1, sy);
+	  DrawLine (sx, sy - D, sx, sy + D + 1);
 	}
       }
@@ -415,11 +434,12 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx + d*z[i] + 1, sy - d*z[i] - 1, sx - d*z[i], sy + d*z[i]);
-	  DrawLine (sx - d*z[i], sy - d*z[i], sx + d*z[i] + 1, sy + d*z[i] + 1);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx - D, sy + D, sx + D + 1, sy - D - 1);
+	  DrawLine (sx - D, sy - D, sx + D + 1, sy + D + 1);
 	}
       }
@@ -429,13 +449,14 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  points[0].x = sx - d*z[i];  points[0].y = sy + 0.58*d*z[i];  
-	  points[1].x = sx + d*z[i];  points[1].y = sy + 0.58*d*z[i];  
-	  points[2].x = sx;           points[2].y = sy - 1.15*d*z[i];  
-	  points[3].x = sx - d*z[i];  points[3].y = sy + 0.58*d*z[i];  
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  points[0].x = sx - D;  points[0].y = sy + 0.58*D;  
+	  points[1].x = sx + D;  points[1].y = sy + 0.58*D;  
+	  points[2].x = sx;      points[2].y = sy - 1.15*D;  
+	  points[3].x = sx - D;  points[3].y = sy + 0.58*D;  
 	  XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
 	}
@@ -445,12 +466,13 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx - d*z[i], sy + 0.58*d*z[i], sx + d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (sx + d*z[i], sy + 0.58*d*z[i], sx,          sy - 1.15*d*z[i]);
-	  DrawLine (sx,          sy - 1.15*d*z[i], sx - d*z[i], sy + 0.58*d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
+	  DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
+	  DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
 	}
       }
@@ -459,12 +481,13 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx, sy, sx - d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (sx, sy, sx + d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (sx, sy, sx,          sy - 1.15*d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx,     sy + 1.15*D);
 	}
       }
@@ -473,10 +496,11 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawCircle (sx, sy, d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawCircle (sx, sy, D);
 	}
       }
@@ -485,14 +509,15 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx + 0.00*d*z[i], sy - 1.00*d*z[i], sx + 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (sx + 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (sx + 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (sx - 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (sx - 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.00*d*z[i], sy - 1.00*d*z[i]);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
+	  DrawLine (sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
+	  DrawLine (sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
+	  DrawLine (sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
+	  DrawLine (sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
 	}
       }
@@ -501,16 +526,17 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx -      d*z[i], sy,               sx - 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (sx - 0.50*d*z[i], sy + 0.87*d*z[i], sx + 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (sx + 0.50*d*z[i], sy + 0.87*d*z[i], sx +      d*z[i], sy);
-
-	  DrawLine (sx +      d*z[i], sy,               sx + 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (sx + 0.50*d*z[i], sy - 0.87*d*z[i], sx - 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (sx - 0.50*d*z[i], sy - 0.87*d*z[i], sx -      d*z[i], sy);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  D = d*z[i];
+	  DrawLine (sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+
+	  DrawLine (sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
 	}
       }
@@ -525,9 +551,9 @@
       for (i = 0; i + 1 < object[0].Npts; i+=2) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx1 = x[i]*mxi + y[i]*mxj + bx;
-	sy1 = x[i]*myi + y[i]*myj + by;
+	sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
 	if (!(finite(x[i+1]) && finite(y[i+1]))) continue;
-	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
-	sy2 = x[i+1]*myi + y[i+1]*myj + by;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx + XCENTER;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by + YCENTER;
 	ClipLine (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
       }
@@ -535,24 +561,30 @@
   } 
   /**** points are not scaled by object.z ***/
+  /** some rules on how the points are drawn:
+      1) the smallest point is always a dot (single pixel)
+      2) the point shape should be invarient on position
+      3) center of point is always center of a pixel
+   **/
   else {
-    d = object[0].size * 0.5 * (graphic->dx + graphic->dy) * 0.003;
+    d = (int)(object[0].size * hypot((float)graphic->dx, (float)graphic->dy) * 0.003);
     x = object[0].x; y = object[0].y;
-    if (object[0].ptype == 0) {	/* filled box */
-      for (i = 0; i < object[0].Npts; i++) {
-	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  FillRectangle (sx - d, sy - d, 2*d, 2*d);
-	}
-      }
-    }
-    if (object[0].ptype == 1) {		/* open box */
-      for (i = 0; i < object[0].Npts; i++) {
-	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+
+    if (object[0].ptype == 0) {	/* filled box : OK */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  FillRectangle (sx - d, sy - d, 2*d + 1, 2*d + 1);
+	}
+      }
+    }
+    if (object[0].ptype == 1) { /* open box : OK*/
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
    	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -562,27 +594,27 @@
       }
     }
-    if (object[0].ptype == 2) { /* cross */
-      for (i = 0; i < object[0].Npts; i++) {
-	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx - d, sy, sx + d + 1, sy);
+    if (object[0].ptype == 2) { /* cross : OK*/
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+ 	  DrawLine (sx - d, sy, sx + d + 1, sy); // DrawLine does NOT draw the end pixel
 	  DrawLine (sx, sy - d, sx, sy + d + 1);
 	}
       }
     }
-    if (object[0].ptype == 3) {		/* x */
-      for (i = 0; i < object[0].Npts; i++) {
-	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+    if (object[0].ptype == 3) { /* x : OK */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
 	  /* XDrawLine is a little funny, this is needed to fix endpost errors */
-	  DrawLine (sx + d + 1, sy - d - 1, sx - d, sy + d);
+	  DrawLine (sx - d, sy + d, sx + d + 1, sy - d - 1);
 	  DrawLine (sx - d, sy - d, sx + d + 1, sy + d + 1);
 	}
@@ -593,6 +625,6 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -609,6 +641,6 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -623,12 +655,12 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
-	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-	{
-	  DrawLine (sx, sy, sx - d, sy + 0.58*d);
-	  DrawLine (sx, sy, sx + d, sy + 0.58*d);
-	  DrawLine (sx, sy, sx,     sy - 1.15*d);
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
+	{
+	  DrawLine (sx, sy, sx - d, sy - 0.58*d);
+	  DrawLine (sx, sy, sx + d, sy - 0.58*d);
+	  DrawLine (sx, sy, sx,     sy + 1.15*d);
 	}
       }
@@ -637,6 +669,6 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -649,6 +681,6 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -665,6 +697,6 @@
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx = x[i]*mxi + y[i]*mxj + bx;
-	sy = x[i]*myi + y[i]*myj + by;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
 	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
@@ -687,8 +719,8 @@
       for (i = 0; i + 1 < object[0].Npts; i+=2) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
-	sx1 = x[i]*mxi + y[i]*mxj + bx;
-	sy1 = x[i]*myi + y[i]*myj + by;
-	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
-	sy2 = x[i+1]*myi + y[i+1]*myj + by;
+	sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx + XCENTER;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by + YCENTER;
 	ClipLine (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
       }
@@ -723,8 +755,8 @@
   for (i = 0; i < object[0].Npts; i++) {
     if (!(finite(x[i]) && finite(y[i]) && finite(dxp[i]))) continue;
-    sx0 = x[i]*mxi + y[i]*mxj + bx;
-    sy0 = x[i]*myi + y[i]*myj + by;
-    sx1 = (x[i] + dxp[i])*mxi + y[i]*mxj + bx;
-    sy1 = (x[i] + dxp[i])*myi + y[i]*myj + by;
+    sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
+    sx1 = (x[i] + dxp[i])*mxi + y[i]*mxj + bx + XCENTER;
+    sy1 = (x[i] + dxp[i])*myi + y[i]*myj + by + YCENTER;
     if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
@@ -740,8 +772,8 @@
     }
     if (!(finite(x[i]) && finite(y[i]) && finite(dxm[i]))) continue;
-    sx0 = x[i]*mxi + y[i]*mxj + bx;
-    sy0 = x[i]*myi + y[i]*myj + by;
-    sx1 = (x[i] - dxm[i])*mxi + y[i]*mxj + bx;
-    sy1 = (x[i] - dxm[i])*myi + y[i]*myj + by;
+    sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
+    sx1 = (x[i] - dxm[i])*mxi + y[i]*mxj + bx + XCENTER;
+    sy1 = (x[i] - dxm[i])*myi + y[i]*myj + by + YCENTER;
     if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
@@ -785,6 +817,6 @@
   for (i = 0; i < object[0].Npts; i++) {
     if (!(finite(x[i]) && finite(y[i]) && finite(dyp[i]))) continue;
-    sx0 = x[i]*mxi + y[i]*mxj + bx;
-    sy0 = x[i]*myi + y[i]*myj + by;
+    sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
     sx1 = sx0 + dyp[i]*mxj;
     sy1 = sy0 + dyp[i]*myj;
@@ -802,8 +834,8 @@
     }
     if (!(finite(x[i]) && finite(y[i]) && finite(dym[i]))) continue;
-    sx0 = x[i]*mxi + y[i]*mxj + bx;
-    sy0 = x[i]*myi + y[i]*myj + by;
-    sx1 = x[i]*mxi + (y[i] - dym[i])*mxj + bx;
-    sy1 = x[i]*myi + (y[i] - dym[i])*myj + by;
+    sx0 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+    sy0 = x[i]*myi + y[i]*myj + by + YCENTER;
+    sx1 = x[i]*mxi + (y[i] - dym[i])*mxj + bx + XCENTER;
+    sy1 = x[i]*myi + (y[i] - dym[i])*myj + by + YCENTER;
     if (((sx0 > graph[0].axis[0].fx) && (sx0 < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
 	 (sy0 < graph[0].axis[1].fy) && (sy0 > graph[0].axis[1].fy + graph[0].axis[1].dfy)) ||
Index: /branches/czw_branch/20110406/Ohana/src/kapa2/src/PSObjects.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/kapa2/src/PSObjects.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/kapa2/src/PSObjects.c	(revision 31606)
@@ -365,7 +365,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	  {
-	    DrawLine (sx - d*z[i], sy + 0.58*d*z[i], sx + d*z[i], sy + 0.58*d*z[i]);
-	    DrawLine (sx + d*z[i], sy + 0.58*d*z[i], sx,          sy - 1.15*d*z[i]);
-	    DrawLine (sx,          sy - 1.15*d*z[i], sx - d*z[i], sy + 0.58*d*z[i]);
+	    DrawLine (sx - d*z[i], sy - 0.58*d*z[i], sx + d*z[i], sy - 0.58*d*z[i]);
+	    DrawLine (sx + d*z[i], sy - 0.58*d*z[i], sx,          sy + 1.15*d*z[i]);
+	    DrawLine (sx,          sy + 1.15*d*z[i], sx - d*z[i], sy - 0.58*d*z[i]);
 	  }
       }
@@ -538,7 +538,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	  {
-	    DrawLine (sx, sy, sx - d, sy - 0.58*d);
-	    DrawLine (sx, sy, sx + d, sy - 0.58*d);
-	    DrawLine (sx, sy, sx,     sy + 1.15*d);
+	    DrawLine (sx, sy, sx - d, sy + 0.58*d);
+	    DrawLine (sx, sy, sx + d, sy + 0.58*d);
+	    DrawLine (sx, sy, sx,     sy - 1.15*d);
 	  }
       }
Index: /branches/czw_branch/20110406/Ohana/src/kapa2/src/bDrawObjects.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/kapa2/src/bDrawObjects.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/kapa2/src/bDrawObjects.c	(revision 31606)
@@ -4,6 +4,6 @@
 # define DrawCircle(BUF,X1,Y1,R) (bDrawCircle (BUF, (X1), (Y1), (R)))
 # define DrawRectangle(BUF,X,Y,dX,dY) (bDrawRectOpen (BUF, (X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
-# define FillRectangle(BUF,X,Y,dX,dY) (bDrawRectFill (BUF, (X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
-# define FillTriangle(BUF,X1,Y1,X2,Y2,X3,Y3) (bDrawTriFill (BUF, (X1), (Y1), (X2), (Y2), (X3), (Y3)))
+# define FillRectangle(BUF,X,Y,dX,dY) (bDrawRectFill (BUF, (X-0.5*dX), (Y-0.5*dY), (X+0.5*dX+1), (Y+0.5*dY+1)))
+# define FillTriangle(BUF,X1,Y1,dX,dY) (bDrawTriFill (BUF, (X1), (Y1), (dX), (dY)))
 # define OpenTriangle(BUF,X1,Y1,X2,Y2,X3,Y3) (bDrawTriOpen (BUF, (X1), (Y1), (X2), (Y2), (X3), (Y3)))
 
@@ -260,5 +260,5 @@
   float *x, *y, *z;
   double mxi, mxj, myi, myj, bxi, bxj, byi, byj, bx, by;
-  double sx, sy, d, sx1, sy1, sx2, sy2;
+  int sx, sy, sx1, sy1, sx2, sy2, d, D;
 
   mxi = graph[0].axis[0].dfx / (object[0].x1 - object[0].x0);
@@ -288,5 +288,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillRectangle (buffer, sx, sy, 2*d*z[i], 2*d*z[i]);
+	  D = d*z[i];
+	  FillRectangle (buffer, sx, sy, 2*D, 2*D);
 	}
       }
@@ -300,5 +301,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawRectangle (buffer, sx, sy, 2*d*z[i], 2*d*z[i]);
+	  D = d*z[i];
+	  DrawRectangle (buffer, sx, sy, 2*D, 2*D);
 	}
       }
@@ -312,6 +314,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (buffer, sx - d*z[i], sy, sx + d*z[i], sy);
-	  DrawLine (buffer, sx, sy - d*z[i], sx, sy + d*z[i]);
+	  D = d*z[i];
+	  DrawLine (buffer, sx - D, sy, sx + D, sy);
+	  DrawLine (buffer, sx, sy - D, sx, sy + D);
 	}
       }
@@ -325,6 +328,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (buffer, sx + d*z[i], sy - d*z[i], sx - d*z[i], sy + d*z[i]);
-	  DrawLine (buffer, sx - d*z[i], sy - d*z[i], sx + d*z[i], sy + d*z[i]);
+	  D = d*z[i];
+	  DrawLine (buffer, sx + D, sy - D, sx - D, sy + D);
+	  DrawLine (buffer, sx - D, sy - D, sx + D, sy + D);
 	}
       }
@@ -338,5 +342,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillTriangle (buffer, sx - d*z[i], sy - 0.58*d*z[i], sx + d*z[i], sy - 0.58*d*z[i], sx, sy + 1.15*d*z[i]);
+	  D = d*z[i];
+	  // FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	  FillTriangle (buffer, sx, sy + 0.58*D, D, -1.73*D);
 	}
       }
@@ -350,5 +356,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  OpenTriangle (buffer, sx - d*z[i], sy + 0.58*d*z[i], sx, sy - 1.15*d*z[i], sx + d*z[i], sy + 0.58*d*z[i]);
+	  D = d*z[i];
+	  OpenTriangle (buffer, sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
 	}
       }
@@ -362,7 +369,8 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (buffer, sx, sy, sx - d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (buffer, sx, sy, sx + d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (buffer, sx, sy, sx,          sy - 1.15*d*z[i]);
+	  D = d*z[i];
+	  DrawLine (buffer, sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (buffer, sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (buffer, sx, sy, sx,     sy + 1.15*D);
 	}
       }
@@ -376,5 +384,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawCircle (buffer, sx, sy, d*z[i]);
+	  D = d*z[i];
+	  DrawCircle (buffer, sx, sy, D);
 	}
       }
@@ -388,9 +397,10 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (buffer, sx + 0.00*d*z[i], sy - 1.00*d*z[i], sx + 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (buffer, sx + 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (buffer, sx + 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (buffer, sx - 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (buffer, sx - 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.00*d*z[i], sy - 1.00*d*z[i]);
+	  D = d*z[i];
+	  DrawLine (buffer, sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
+	  DrawLine (buffer, sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
+	  DrawLine (buffer, sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
+	  DrawLine (buffer, sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
+	  DrawLine (buffer, sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
 	}
       }
@@ -404,11 +414,11 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (buffer, sx -      d*z[i], sy,               sx - 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (buffer, sx - 0.50*d*z[i], sy + 0.87*d*z[i], sx + 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (buffer, sx + 0.50*d*z[i], sy + 0.87*d*z[i], sx +      d*z[i], sy);
-
-	  DrawLine (buffer, sx +      d*z[i], sy,               sx + 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (buffer, sx + 0.50*d*z[i], sy - 0.87*d*z[i], sx - 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (buffer, sx - 0.50*d*z[i], sy - 0.87*d*z[i], sx -      d*z[i], sy);
+	  D = d*z[i];
+	  DrawLine (buffer, sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (buffer, sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (buffer, sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+	  DrawLine (buffer, sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (buffer, sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (buffer, sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
 	}
       }
@@ -431,6 +441,7 @@
     }
   } else {
-    d = object[0].size * 0.5 * (graphic->dx + graphic->dy) * 0.003;
+    d = (int)(object[0].size * hypot((float)graphic->dx, (float)graphic->dy) * 0.003);
     x = object[0].x; y = object[0].y;
+
     if (object[0].ptype == 0) {	/* filled box */
       for (i = 0; i < object[0].Npts; i++) {
@@ -457,5 +468,5 @@
       }
     }
-    if (object[0].ptype == 2) { /* cross */
+    if (object[0].ptype == 2) { /* cross : OK */
       for (i = 0; i < object[0].Npts; i++) {
 	if (!(finite(x[i]) && finite(y[i]))) continue;
@@ -491,5 +502,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillTriangle (buffer, sx - d, sy - 0.58*d, sx + d, sy - 0.58*d, sx, sy + 1.15*d);
+	  FillTriangle (buffer, sx, sy + 0.58*d, d, -1.73*d);
 	}
       }
Index: /branches/czw_branch/20110406/Ohana/src/libdvo/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libdvo/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libdvo/Makefile	(revision 31606)
@@ -101,21 +101,21 @@
 
 $(AINC)/autocode.h: $(AINCS) $(ADEF)/autocode.h $(ADEF)/common.h
-	@echo "make $@ from $^"
-	cd $(AUTO) && make $@
+	@echo "$(MAKE) $@ from $^"
+	cd $(AUTO) && $(MAKE) $@
 
 # generic rule for AINCS
 $(AINC)/%.h : $(ADEF)/%.d $(ADEF)/autocode.h $(ADEF)/common.h
-	@echo "make $@ from $^"
-	cd $(AUTO) && make $@
+	@echo "$(MAKE) $@ from $^"
+	cd $(AUTO) && $(MAKE) $@
 
 # generic rule for ASRC
 $(ASRC)/%.c : $(ADEF)/%.d $(ADEF)/autocode.c $(AINC)/%.h
-	@echo "make $@ from $^"
-	cd $(AUTO) && make $@
+	@echo "$(MAKE) $@ from $^"
+	cd $(AUTO) && $(MAKE) $@
 
 # generic rule for AOBJS
 $(ASRC)/%.$(ARCH).o : $(ASRC)/%.c
-	@echo "make $@ from $^"
-	cd $(AUTO) && make $@
+	@echo "$(MAKE) $@ from $^"
+	cd $(AUTO) && $(MAKE) $@
 
 tabletest: install
@@ -124,5 +124,5 @@
 clean: cleandef
 cleandef:
-	cd $(AUTO) && make clean
+	cd $(AUTO) && $(MAKE) clean
 
 .PRECIOUS: $(ASRC)/%.c
Index: /branches/czw_branch/20110406/Ohana/src/libdvo/include/dvo.h
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libdvo/include/dvo.h	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libdvo/include/dvo.h	(revision 31606)
@@ -20,7 +20,7 @@
   DVO_FORMAT_PS1_DEV_2,
   DVO_FORMAT_PS1_DEV_3,
+  DVO_FORMAT_PS1_REF,
   DVO_FORMAT_PS1_V1,
   DVO_FORMAT_PS1_V2,
-  DVO_FORMAT_PS1_REF
 } DVOTableFormat;
 
@@ -210,4 +210,31 @@
 } PhotCodeData;
 
+// a reduced-subset structure for relphot
+typedef struct {
+  double         R;
+  double         D;
+  unsigned short Nmeasure;
+  int            measureOffset;
+  uint32_t       flags;
+} AverageTiny;
+
+// a reduced-subset structure for relphot
+typedef struct {
+  float          dR;
+  float          dD;
+  float          M;
+  float          Mcal;
+  float          dM;
+  float          airmass;
+  float          Xccd;
+  float          Yccd;
+  float          dt;
+  int   	 t;
+  unsigned int   averef;
+  unsigned int   imageID;
+  unsigned int   dbFlags;
+  unsigned short photcode;
+} MeasureTiny;
+
 /* a catalog contains this data */
 typedef struct Catalog {
@@ -226,4 +253,8 @@
   off_t Naves_disk, Nmeas_disk, Nmiss_disk, Nsecf_disk; /* current number of each component on disk */
   off_t Naves_off,  Nmeas_off,  Nmiss_off,  Nsecf_off;  /* index of first loaded data value */
+
+  // note that we use these for the full-sky relphot analysis
+  AverageTiny *averageT;
+  MeasureTiny *measureT; 
 
   /* the Nsecf_* values above are number of table rows (eg, Naverage*Nsecfilt) */
@@ -330,4 +361,19 @@
 int PhotColor (Average *average, SecFilt *secfilt, Measure *measure, int c1, int c2, double *color);
 
+float PhotInstTiny (MeasureTiny *measure);
+float PhotCatTiny (MeasureTiny *measure);
+float PhotAperTiny (MeasureTiny *measure);
+float PhotSysTiny (MeasureTiny *measure, AverageTiny *average, SecFilt *secfilt);
+float PhotRelTiny (MeasureTiny *measure, AverageTiny *average, SecFilt *secfilt);
+float PhotCalTiny (MeasureTiny *thisone, AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, PhotCode *code);
+float PhotAveTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt);
+float PhotRefTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure);
+float PhotXmTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt);
+float PhotdMTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt);
+
+float PhotColorForCodeTiny (AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, PhotCode *code);
+int PhotColorTiny (AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, int c1, int c2, double *color);
+
+
 PhotCodeData *GetPhotcodeTable (void);
 void SetPhotcodeTable (PhotCodeData *);
Index: /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_catalog_split.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 31606)
@@ -448,5 +448,6 @@
     catalog[0].measure = FtableToMeasure (&ftable, &Nmeasure, &catalog[0].catformat);
     if (Nmeasure != Nrows) {
-      fprintf (stderr, "Warning: mismatch between Nmeasure in PHU and Table headers ("OFF_T_FMT" vs "OFF_T_FMT")\n",  Nmeasure,  Nrows);
+      // XXX this condition denotes the eof has been reached; not an error or a warning
+      // fprintf (stderr, "Warning: mismatch between Nmeasure in PHU and Table headers ("OFF_T_FMT" vs "OFF_T_FMT")\n",  Nmeasure,  Nrows);
     }
     gfits_free_header (&header);
Index: /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_photcode_ops.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 31606)
@@ -536,4 +536,324 @@
   return (TRUE);
 }
+
+/******** alternate photometry conversion functions using MeasureTiny and AverageTiny *********/
+float PhotInstTiny (MeasureTiny *measure) {
+
+  int Np;
+  float M;
+
+  Np = photcodes[0].hashcode[measure[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    M = measure[0].M;
+    return (M);
+  }
+
+  M = measure[0].M - measure[0].dt - ZERO_POINT;
+	  
+  return (M);
+
+}
+
+float PhotCatTiny (MeasureTiny *measure) {
+
+  int Np;
+  float Mcat;
+  PhotCode *code;
+
+  Np = photcodes[0].hashcode[measure[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mcat = measure[0].M;
+    return (Mcat);
+  }
+  code = &photcodes[0].code[Np];
+  Mcat = measure[0].M - ZERO_POINT + code[0].K*(measure[0].airmass - 1.000) + SCALE*code[0].C;
+  
+  return (Mcat);
+}
+
+# if (0)
+float PhotAperTiny (MeasureTiny *measure) {
+
+  int Np;
+  float Mcat;
+  PhotCode *code;
+
+  Np = photcodes[0].hashcode[measure[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mcat = measure[0].Map;
+    return (Mcat);
+  }
+  code = &photcodes[0].code[Np];
+  Mcat = measure[0].Map - ZERO_POINT + code[0].K*(measure[0].airmass - 1.000) + SCALE*code[0].C;
+  
+  return (Mcat);
+}
+# endif
+
+float PhotSysTiny (MeasureTiny *measure, AverageTiny *average, SecFilt *secfilt) {
+
+  int i, Np;
+  float Mcat, Mcol, Msys, mc, Mc;
+  PhotCode *code;
+
+  Np = photcodes[0].hashcode[measure[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Msys = measure[0].M;
+    return (Msys);
+  }
+  code = &photcodes[0].code[Np];
+  Mcat = measure[0].M - ZERO_POINT + code[0].K*(measure[0].airmass - 1.000) + SCALE*code[0].C;
+
+  /* for DEP, color must be made of PRI/SEC */
+  mc = PhotColorForCodeTiny (average, secfilt, NULL, code);
+  if (isnan(mc)) return (Mcat);
+  mc = mc - SCALE*code[0].dX;
+
+  Mc = mc;
+  Mcol = 0;
+  for (i = 0; i < code[0].Nc; i++) {
+    Mcol += code[0].X[i]*Mc;
+    Mc *= mc;
+  }
+  Msys = Mcat + Mcol;
+  return (Msys);
+}
+
+float PhotRelTiny (MeasureTiny *measure, AverageTiny *average, SecFilt *secfilt) {
+
+  int i, Np;
+  float Mcat, Mcol, Mrel, mc, Mc;
+  PhotCode *code;
+
+  Np = photcodes[0].hashcode[measure[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mcat = measure[0].M;
+    return (Mcat);
+  }
+  code = &photcodes[0].code[Np];
+  Mrel = measure[0].M - ZERO_POINT + code[0].K*(measure[0].airmass - 1.000) + SCALE*code[0].C - measure[0].Mcal;
+
+  /* for DEP, color must be made of PRI/SEC */
+  mc = PhotColorForCodeTiny (average, secfilt, NULL, code);
+  if (isnan(mc)) return (Mrel);
+  mc = mc - SCALE*code[0].dX;
+
+  Mc = mc;
+  Mcol = 0;
+  for (i = 0; i < code[0].Nc; i++) {
+    Mcol += code[0].X[i]*Mc;
+    Mc *= mc;    /* the 0.001 is needed for higher order terms to keep the units mag = mag^n */
+  }
+  Mrel += Mcol;
+  return (Mrel);
+}
+
+/* return calibrated magnitude from measure for given photcode */
+float PhotCalTiny (MeasureTiny *thisone, AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, PhotCode *code) {
+
+  int i, Np; 
+  float Mcal, Mrel, Mcol, mc, Mc;
+
+  if (code == NULL) return NAN;
+
+  /* code must be the matching PRI/SEC code for this measurement or an equivalent ALT */
+  Np = photcodes[0].hashcode[thisone[0].photcode];
+  if (Np == -1) return (NAN);
+
+  if (photcodes[0].code[Np].type == PHOT_REF) {
+    Mrel = thisone[0].M;
+    return (Mrel);
+  }
+  if (code[0].code != photcodes[0].code[Np].equiv) return (NAN);
+
+  Mcal = PhotRelTiny (thisone, average, secfilt) + SCALE*code[0].C;
+
+  mc = PhotColorForCodeTiny (average, secfilt, measure, code);
+  if (isnan(mc)) return (Mcal);
+  mc = mc - SCALE*code[0].dX;
+
+  Mc = mc;
+  Mcol = 0;
+  for (i = 0; i < code[0].Nc; i++) {
+    Mcol += code[0].X[i]*Mc;
+    Mc *= mc;
+  }
+  Mcal += Mcol;
+  return (Mcal);
+}
+
+/* color term may not use DEP magnitude */
+float PhotColorForCodeTiny (AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, PhotCode *code) {
+
+  int i, Ns1, Ns2, Ns;
+  float m1, m2, mc;
+  PhotCode *color;
+
+  m1 = m2 = NAN;
+
+  if (measure == NULL) {
+    Ns1 = photcodes[0].hashNsec[code[0].c1];
+    Ns2 = photcodes[0].hashNsec[code[0].c2];
+  
+    m1 = (Ns1 == -1) ? NAN : secfilt[Ns1].M;
+    m2 = (Ns2 == -1) ? NAN : secfilt[Ns2].M;
+    mc = (isnan(m1) || isnan(m2)) ? NAN : (m1 - m2);
+    return (mc);
+  }
+
+  /* find magnitude matching first color term */
+  color = GetPhotcodebyCode (code[0].c1);
+  if (color == NULL) return (NAN);
+  if (color[0].type == PHOT_REF) {
+    for (i = 0; (i < average[0].Nmeasure) && (isnan(m1)); i++) {
+      if (measure[i].photcode == color[0].code) {
+	m1 = measure[i].M;
+      }
+    }
+  } else {
+    Ns = photcodes[0].hashNsec[color[0].code];
+    m1 = (Ns == -1) ? NAN : secfilt[Ns].M;
+  }	
+
+  /* find magnitude matching second color term */
+  color = GetPhotcodebyCode (code[0].c2);
+  if (color == NULL) return (NAN);
+  if (color[0].type == PHOT_REF) {
+    for (i = 0; (i < average[0].Nmeasure) && (isnan(m2)); i++) {
+      if (measure[i].photcode == color[0].code) {
+	m2 = measure[i].M;
+      }
+    }
+  } else {
+    Ns = photcodes[0].hashNsec[color[0].code];
+    m2 = (Ns == -1) ? NAN : secfilt[Ns].M;
+  }	
+  mc = (isnan(m1) || isnan(m2)) ? NAN : (m1 - m2);
+  return (mc);
+}
+
+/* return calibrated magnitude from average/secfilt for given photcode */
+float PhotRefTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure) {
+
+  int i, Ns;
+  float Mave, Mref, Mcol, mc;
+  double Mc;
+
+  if (code == NULL) return NAN;
+
+  Ns = photcodes[0].hashNsec[code[0].code];
+  Mave = (Ns == -1) ? NAN : secfilt[Ns].M;
+  Mref = Mave + SCALE*code[0].C;
+
+  mc = PhotColorForCodeTiny (average, secfilt, measure, code);
+  if (isnan(mc)) return (Mref);
+  mc = mc - SCALE*code[0].dX;
+
+  Mc = mc;
+  Mcol = 0;
+  for (i = 0; i < code[0].Nc; i++) {
+    Mcol += code[0].X[i]*Mc;
+    Mc *= mc;    /* the 0.001 is needed for higher order terms to keep the units mag = mag^n */
+  }
+  Mref += Mcol;
+  return (Mref);
+}
+
+/***/
+float PhotAveTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt) {
+
+  int Ns;
+  float Mave;
+
+  if (code == NULL) return NAN;
+
+  Ns = photcodes[0].hashNsec[code[0].code];
+  Mave = (Ns == -1) ? NAN : secfilt[Ns].M;
+  return (Mave);
+}
+
+float PhotdMTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt) {
+
+  int Ns;
+  float dM;
+
+  if (code == NULL) return NAN;
+
+  Ns = photcodes[0].hashNsec[code[0].code];
+  dM  = (Ns == -1) ? NAN : secfilt[Ns].dM;
+  return (dM);
+}
+
+// XXX return NAN or NAN_S_SHORT? (secfilt->Xm is short)
+float PhotXmTiny (PhotCode *code, AverageTiny *average, SecFilt *secfilt) {
+
+  int Ns;
+  short Mi;
+  float Xm;
+
+  if (code == NULL) return NAN;
+
+  Ns = photcodes[0].hashNsec[code[0].code];
+  Mi = (Ns == -1) ? NAN : secfilt[Ns].Xm;
+  Xm = (isnan(Mi)) ? -1.0 : pow (10.0, 0.01*Mi);
+  return (Xm);
+}
+
+/* given a photcode pair c1 & c2, return the color of this star (NaN if not found) */
+int PhotColorTiny (AverageTiny *average, SecFilt *secfilt, MeasureTiny *measure, int c1, int c2, double *color) {
+
+  int i, Ns;
+  double M1, M2, dM;
+  PhotCode *code;
+  
+  code = GetPhotcodebyCode (c1);
+  if (code == NULL) return (FALSE);
+  if (code[0].type == PHOT_REF) {
+    for (i = 0; i < average[0].Nmeasure; i++) {
+      if (measure[i].photcode == c1) {
+	M1 = measure[i].M;
+	goto filter1;
+      }
+    }	
+    return (FALSE);
+  } else {
+    Ns = photcodes[0].hashNsec[code[0].code];
+    M1 = (Ns == -1) ? NAN : secfilt[Ns].M;
+  }	
+
+filter1:
+  code = GetPhotcodebyCode (c2);
+  if (code == NULL) return (FALSE);
+  if (code[0].type == PHOT_REF) {
+    for (i = 0; i < average[0].Nmeasure; i++) {
+      if (measure[i].photcode == c2) {
+	M2 = measure[i].M;
+	goto filter2;
+      }
+    }	
+    return (FALSE);
+  } else {
+    Ns = photcodes[0].hashNsec[code[0].code];
+    M2 = (Ns == -1) ? NAN : secfilt[Ns].M;
+  }	
+  
+filter2:
+
+  dM = M1 - M2;
+  *color = dM;
+  
+  return (TRUE);
+}
+/***********************************************/
 
 // Create a map between the secfilt values from one photcode table to another
Index: /branches/czw_branch/20110406/Ohana/src/libkapa/include/kapa.h
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libkapa/include/kapa.h	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libkapa/include/kapa.h	(revision 31606)
@@ -255,5 +255,5 @@
 void bDrawRectFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2);
 void bDrawTriOpen  (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3);
-void bDrawTriFill  (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3);
+void bDrawTriFill  (bDrawBuffer *buffer, double x1, double y1, double dx, double dy);
 
 /* bDrawRotFont.c */
Index: /branches/czw_branch/20110406/Ohana/src/libkapa/src/bDrawFuncs.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 31606)
@@ -134,6 +134,6 @@
   Y2 = MIN (MAX (ROUND (y2), 1), buffer[0].Ny - 1);
 
-  bDrawLineHorizontal (buffer, X1, X2, Y1);
-  bDrawLineHorizontal (buffer, X1, X2, Y2);
+  bDrawLineHorizontal (buffer, X1, X2 + 1, Y1);
+  bDrawLineHorizontal (buffer, X1, X2 + 1, Y2);
   bDrawLineVertical   (buffer, X1, Y1, Y2);
   bDrawLineVertical   (buffer, X2, Y1, Y2);
@@ -275,7 +275,53 @@
 }
 
-void bDrawTriFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3) {
-
-  bDrawTriOpen (buffer, x1, y1, x2, y2, x3, y3);
+// upright triangle with base of width 2 dX + 1, height of dY, center of base at x1, y1
+void bDrawTriFill (bDrawBuffer *buffer, double x1, double y1, double dx, double dy) {
+
+  int xs, xe, x, y;
+  float e, m;
+
+  double dX = fabs(dx);
+  
+  xs = x1 - dX;
+  xe = x1 + dX + 1;
+  e = 0;
+  m = dX / dy;
+
+  if (dy > 0.0) {
+    for (y = y1; y < y1 + dy + 1; y++) {
+      for (x = xs; x < xe; x++) {
+	bDrawPoint (buffer, x, y);
+      }
+      e += m;
+      if (e > 0.5) {
+	xs ++;
+	xe --;
+	e -= 1.0;
+      }
+      if (e < -0.5) {
+	xs ++;
+	xe --;
+	e += 1.0;
+      }
+    }    
+  } else {
+    for (y = y1; y > y1 + dy - 1; y--) {
+      for (x = xs; x < xe; x++) {
+	bDrawPoint (buffer, x, y);
+      }
+      e += m;
+      if (e > 0.5) {
+	xs ++;
+	xe --;
+	e -= 1.0;
+      }
+      if (e < -0.5) {
+	xs ++;
+	xe --;
+	e += 1.0;
+      }
+    }    
+  }
+ 
   return;
 }
Index: /branches/czw_branch/20110406/Ohana/src/libohana/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/libohana/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/libohana/Makefile	(revision 31606)
@@ -54,5 +54,5 @@
 testcode: install $(TEST)
 test:
-	make testcode
+	$(MAKE) testcode
 	for i in $(TEST); do $$i; done
 
Index: /branches/czw_branch/20110406/Ohana/src/misc/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/misc/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/misc/Makefile	(revision 31606)
@@ -37,5 +37,5 @@
 
 cfhtlog:
-	make $(DESTBIN)/cfhtlog
+	$(MAKE) $(DESTBIN)/cfhtlog
 
 # copied from Makefile.Common : use a single c file: foo : foo.c
@@ -56,8 +56,8 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(PROGRAMS); do make $$i.install || exit; done
+	for i in $(PROGRAMS); do $(MAKE) $$i.install || exit; done
 
 %.clean:
Index: /branches/czw_branch/20110406/Ohana/src/opihi/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/Makefile	(revision 31606)
@@ -23,30 +23,30 @@
 
 all:
-	for i in $(PROGRAM) $(SPECIAL); do make $$i || exit; done
-	make pantasks_client
-	make pantasks_server
+	for i in $(PROGRAM) $(SPECIAL); do $(MAKE) $$i || exit; done
+	$(MAKE) pantasks_client
+	$(MAKE) pantasks_server
 
 libs:
-	for i in $(LIBS); do make $$i || exit; done
+	for i in $(LIBS); do $(MAKE) $$i || exit; done
 
 extras:
-	for i in $(EXTRAS); do make $$i || exit; done
+	for i in $(EXTRAS); do $(MAKE) $$i || exit; done
 
 install:
-	for i in $(PROGRAM) $(SPECIAL); do make $$i.install || exit; done
-	make pantasks_client.install
-	make pantasks_server.install
+	for i in $(PROGRAM) $(SPECIAL); do $(MAKE) $$i.install || exit; done
+	$(MAKE) pantasks_client.install
+	$(MAKE) pantasks_server.install
 
 extras-install:
-	for i in $(EXTRAS); do make $$i.install || exit; done
+	for i in $(EXTRAS); do $(MAKE) $$i.install || exit; done
 
 clean:
-	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do make $$i.clean || exit; done
+	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do $(MAKE) $$i.clean || exit; done
 
 libs-uninstall:
-	for i in $(LIBS); do make $$i.uninstall || exit; done
+	for i in $(LIBS); do $(MAKE) $$i.uninstall || exit; done
 
 dist: clean
-	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do make $$i.dist || exit; done
+	for i in $(PROGRAM) $(SPECIAL) $(EXTRAS) $(LIBS); do $(MAKE) $$i.dist || exit; done
 	rm -rf bin
 	rm -rf lib
@@ -55,27 +55,27 @@
 
 pantasks_client pantasks_server:
-	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+	if [ -d pantasks ]; then (cd pantasks && $(MAKE) $@); fi
 
 pantasks_client.install: pantasks_client
-	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+	if [ -d pantasks ]; then (cd pantasks && $(MAKE) $@); fi
 
 pantasks_server.install: pantasks_server
-	if [ -d pantasks ]; then (cd pantasks && make $@); fi
+	if [ -d pantasks ]; then (cd pantasks && $(MAKE) $@); fi
 
 $(PROGRAM) $(LIBS) $(EXTRAS):
-	if [ -d "$@" ]; then (cd $@ && make); fi
+	if [ -d "$@" ]; then (cd $@ && $(MAKE)); fi
 
 %.install:
-	if [ -d "$*" ]; then make $*; fi
-	if [ -d "$*" ]; then (cd $* && make install); fi
+	if [ -d "$*" ]; then $(MAKE) $*; fi
+	if [ -d "$*" ]; then (cd $* && $(MAKE) install); fi
 
 %.clean:
-	if [ -d "$*" ]; then (cd $* && make clean); fi
+	if [ -d "$*" ]; then (cd $* && $(MAKE) clean); fi
 
 %.dist:
-	if [ -d "$*" ]; then (cd $* && make dist); fi
+	if [ -d "$*" ]; then (cd $* && $(MAKE) dist); fi
 
 %.uninstall:
-	if [ -d "$*" ]; then (cd $* && make uninstall); fi
+	if [ -d "$*" ]; then (cd $* && $(MAKE) uninstall); fi
 
 .PHONY: $(PROGRAM) $(LIBS) pantasks_server pantasks_client
Index: /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/Makefile	(revision 31606)
@@ -141,4 +141,5 @@
 $(SRC)/vpop.$(ARCH).o		   \
 $(SRC)/vroll.$(ARCH).o		   \
+$(SRC)/vshift.$(ARCH).o		   \
 $(SRC)/vsmooth.$(ARCH).o	   \
 $(SRC)/vstats.$(ARCH).o		   \
Index: /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/gridify.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/gridify.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/gridify.c	(revision 31606)
@@ -4,5 +4,5 @@
 
   int i, Nx, Ny, Xb, Yb, Normalize, N;
-  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY, initValue;
   float *buf, *val;
   int *Nval;
@@ -15,4 +15,11 @@
     remove_argument (N, &argc, argv);
     Normalize = FALSE;
+  }
+
+  initValue = 0.0;
+  if ((N = get_argument (argc, argv, "-init-value"))) {
+    remove_argument (N, &argc, argv);
+    initValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
   }
 
@@ -69,7 +76,7 @@
   buf = (float *) bf[0].matrix.buffer;
   for (i = 0; i < Nx*Ny; i++) {
+    buf[i] = initValue;
     if (Normalize) {
       if (Nval[i] == 0) {
-	buf[i] = 0;
 	continue;
       }
Index: /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/init.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/init.c	(revision 31606)
@@ -130,4 +130,5 @@
 int vstats           PROTO((int, char **));
 int vroll            PROTO((int, char **));
+int vshift           PROTO((int, char **));
 int vpop             PROTO((int, char **));
 int vsmooth          PROTO((int, char **));
@@ -274,5 +275,6 @@
   {1, "vmaxwell",     vmaxwell,         "fit a Maxwellian to a vector"},
   {1, "vpop",         vpop,             "remove first element of a vector"},
-  {1, "vroll",        vroll,            "roll vector elements"},
+  {1, "vroll",        vroll,            "roll vector elements by 1 entry"},
+  {1, "vshift",       vshift,           "shift vector elements by arbitrary amount"},
   {1, "vsmooth",      vsmooth,          "Gaussian smooth of a vector"},
   {1, "vstats",       vstats,           "statistics on a vector"},
Index: /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/vshift.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/vshift.c	(revision 31606)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/cmd.data/vshift.c	(revision 31606)
@@ -0,0 +1,73 @@
+# include "data.h"
+
+int vshift (int argc, char **argv) {
+
+  int isPos, N, Npix, Nshift, delta, ROLL;
+  Vector *ivec, *ovec;
+
+  ROLL = FALSE;
+  if ((N = get_argument (argc, argv, "-roll"))) {
+    remove_argument (N, &argc, argv);
+    ROLL = TRUE;
+  }
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: vshift (input) (output) (delta) [-roll]\n");
+    gprint (GP_ERR, "  shift vector by (delta) elements\n");
+    gprint (GP_ERR, "  a positive value move element (i) to (i+delta)\n");
+    gprint (GP_ERR, "  -roll : move dropped values to the other size (no elements are lost)\n");
+    return (FALSE);
+  }
+
+  if ((ivec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ovec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  delta = atoi(argv[3]);
+  isPos = delta > 0;
+  delta = abs(delta);
+    
+  ResetVector (ovec, ivec->type, ivec->Nelements);
+
+  Npix = ivec[0].Nelements;
+  if (delta > Npix) {
+    if (!ROLL) {
+      if (ivec[0].type == OPIHI_FLT) {
+	memset (ovec[0].elements.Flt, 0, Npix*sizeof(opihi_flt));
+      } else {
+	memset (ovec[0].elements.Flt, 0, Npix*sizeof(opihi_flt));
+      }
+      return TRUE;
+    }
+    delta = delta % Npix;
+  }
+
+  if (ivec[0].type == OPIHI_FLT) {
+    memset (ovec[0].elements.Flt, 0, Npix*sizeof(opihi_flt));
+    Nshift = Npix - delta;
+    if (isPos) {
+      memcpy (&ovec[0].elements.Flt[delta], &ivec[0].elements.Flt[0], Nshift*sizeof(opihi_flt));
+      if (ROLL) {
+	memcpy (&ovec[0].elements.Flt[0], &ivec[0].elements.Flt[Nshift], delta*sizeof(opihi_flt));
+      } 
+    } else {
+      memcpy (&ovec[0].elements.Flt[0], &ivec[0].elements.Flt[delta], Nshift*sizeof(opihi_flt));
+      if (ROLL) {
+	memcpy (&ovec[0].elements.Flt[Nshift], &ivec[0].elements.Flt[0], delta*sizeof(opihi_flt));
+      }
+    }
+  } else {
+    memset (ovec[0].elements.Int, 0, Npix*sizeof(opihi_int));
+    Nshift = Npix - delta;
+    if (isPos) {
+      memcpy (&ovec[0].elements.Int[delta], &ivec[0].elements.Int[0], Nshift*sizeof(opihi_int));
+      if (ROLL) {
+	memcpy (&ovec[0].elements.Int[0], &ivec[0].elements.Int[Nshift], delta*sizeof(opihi_int));
+      } 
+    } else {
+      memcpy (&ovec[0].elements.Int[0], &ivec[0].elements.Int[delta], Nshift*sizeof(opihi_int));
+      if (ROLL) {
+	memcpy (&ovec[0].elements.Int[Nshift], &ivec[0].elements.Int[0], delta*sizeof(opihi_int));
+      }
+    }
+  }
+  return (TRUE);
+}
Index: /branches/czw_branch/20110406/Ohana/src/opihi/dvo/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/dvo/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/dvo/Makefile	(revision 31606)
@@ -80,4 +80,5 @@
 $(SRC)/mextract.$(ARCH).o	  	\
 $(SRC)/mmextract.$(ARCH).o	  	\
+$(SRC)/objectcoverage.$(ARCH).o	  	\
 $(SRC)/photcodes.$(ARCH).o	  	\
 $(SRC)/pmeasure.$(ARCH).o	  	\
Index: /branches/czw_branch/20110406/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/dvo/avextract.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/dvo/avextract.c	(revision 31606)
@@ -5,5 +5,5 @@
   off_t i, j, n, m;
   int N, Npts, NPTS, last, next, state, Nfields, Nreturn, Ncstack, Nstack;
-  int Nsecfilt, mode, VERBOSE;
+  int Nsecfilt, mode, VERBOSE, needMeasures;
   char **cstack, name[1024];
   void *Signal;
@@ -101,4 +101,13 @@
   }
 
+  // check the requested fields : are all average/secfilt entries, or do we need measures?
+  needMeasures = FALSE;
+  for (i = 0; !needMeasures && (i < Nfields); i++) {
+    if (fields[i].magMode == MAG_NONE) continue;
+    if (fields[i].photcode == NULL) continue; // assert this?
+    if (fields[i].photcode[0].type == PHOT_REF) needMeasures = TRUE;
+    if (fields[i].photcode[0].type == PHOT_DEP) needMeasures = TRUE;
+  }
+
   // grab data from all selected sky regions
   Signal = signal (SIGINT, handle_interrupt);
@@ -107,5 +116,8 @@
     /* lock, load, unlock catalog */
     catalog.filename = skylist[0].filename[i];
-    catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_SECF;
+    catalog.catflags = LOAD_AVES | LOAD_SECF;
+    if (needMeasures) {
+      catalog.catflags |= LOAD_MEAS;
+    }
     catalog.Nsecfilt = 0;
 
Index: /branches/czw_branch/20110406/Ohana/src/opihi/dvo/init.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/dvo/init.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/dvo/init.c	(revision 31606)
@@ -40,5 +40,6 @@
 int lightcurve      PROTO((int, char **));
 int mextract        PROTO((int, char **));
-int mmextract        PROTO((int, char **));
+int mmextract       PROTO((int, char **));
+int objectcoverage  PROTO((int, char **));
 int pcat            PROTO((int, char **));
 int photcodes       PROTO((int, char **));
@@ -92,4 +93,5 @@
   {1, "mextract",    mextract,     "extract measure data values"},
   {1, "mmextract",   mmextract,    "extract joined measurements"},
+  {1, "objectcoverage", objectcoverage, "plot catalog boundaries"},
   {1, "pcat",        skycat,       "plot catalog boundaries"},
   {1, "photcodes",   photcodes,    "list photometry codes"},
Index: /branches/czw_branch/20110406/Ohana/src/opihi/dvo/objectcoverage.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/opihi/dvo/objectcoverage.c	(revision 31606)
+++ /branches/czw_branch/20110406/Ohana/src/opihi/dvo/objectcoverage.c	(revision 31606)
@@ -0,0 +1,235 @@
+# include "dvoshell.h"
+
+int wordhash (char *word);
+
+int objectcoverage (int argc, char **argv) {
+
+  void *Signal;
+  int ShowDensity;
+  int N, status, TimeSelect, xs, ys;
+  time_t tzero, tend;
+  double pixscale, r, d, Xs, Ys, trange, RaCenter, DecCenter;
+  char projection[16];
+  float *V;
+  int k, j, invalid, Nx, Ny;
+  Buffer *buf;
+  Coords coords;
+  int Nsecfilt;
+  SkyList *skylist;
+  SkyRegionSelection *selection;
+
+  Catalog catalog; 
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  skylist = NULL;
+  selection = NULL;
+  RaCenter = 0.0;
+  DecCenter = 0.0;
+  if ((selection = SetRegionSelection (&argc, argv)) == NULL) goto escape;
+  if ((N = get_argument (argc, argv, "-center"))) {
+    remove_argument (N, &argc, argv);
+    RaCenter = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    DecCenter = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Nx = 0;
+  Ny = 0;
+  if ((N = get_argument (argc, argv, "-size"))) {
+    remove_argument (N, &argc, argv);
+    Nx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    Ny = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  pixscale = 1.0;
+  if ((N = get_argument (argc, argv, "-scale"))) {
+    remove_argument (N, &argc, argv);
+    pixscale = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  ShowDensity = FALSE;
+  if ((N = get_argument (argc, argv, "-density"))) {
+    remove_argument (N, &argc, argv);
+    ShowDensity = TRUE;
+  }
+
+  strcpy (projection, "DEC--AIT");
+  if ((N = get_argument (argc, argv, "-proj"))) {
+    remove_argument (N, &argc, argv);
+    if (!strcasecmp(argv[N], "TAN")) {
+	strcpy (projection, "DEC--TAN");
+    }	
+    if (!strcasecmp(argv[N], "SIN")) {
+	strcpy (projection, "DEC--SIN");
+    }	
+    if (!strcasecmp(argv[N], "GLS")) {
+	strcpy (projection, "DEC--GLS");
+    }	
+    if (!strcasecmp(argv[N], "PAR")) {
+	strcpy (projection, "DEC--PAR");
+    }	
+    remove_argument (N, &argc, argv);
+  }
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!ohana_str_to_time (argv[N], &tzero)) { 
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!ohana_str_to_dtime (argv[N], &trange)) { 
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-trange"))) {
+    remove_argument (N, &argc, argv);
+    if (!ohana_str_to_time (argv[N], &tzero)) { 
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!ohana_str_to_time (argv[N], &tend)) { 
+      gprint (GP_ERR, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: objectcoverage (buffer) (photcode)\n");
+    gprint (GP_ERR, "  options: [-scale pixscale] [-center ra dec] [-size Nx Nx] [-proj projection] [-time start range] [-trange start stop] [-name name] [+mosaic] [-mosaic] [-density]\n");
+    gprint (GP_ERR, "       (buffer) saves bitmapped image\n");
+    gprint (GP_ERR, "       (photcode) ..........\n");
+    gprint (GP_ERR, "       -scale (pixscale)  : specifies the pixel size in degrees [1.0]\n");
+    gprint (GP_ERR, "       -center (ra) (dec) : specifies the center of the field [0.0, 0.0]\n");
+    gprint (GP_ERR, "       -size (Nx) (Ny)    : specifies the size of the image [360/scale, 180/scale]\n");
+    gprint (GP_ERR, "       -proj (projection) : specifies the projection choice [AIT]\n");
+    gprint (GP_ERR, "       -density           : create image with relative density (else binary on/off)\n");
+    gprint (GP_ERR, "       note: we need 64800 / (pixscale)^2 pixels to represent the sky\n");
+    return (FALSE);
+  }
+  
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  int myCode = GetPhotcodeCodebyName (argv[2]);
+  if (myCode == 0) {
+      gprint (GP_ERR, "invalid photcode\n");
+      return (FALSE);
+  }
+
+  if (!Nx || !Ny) {
+    Nx = 360/pixscale;
+    Ny = 180/pixscale;
+  }
+
+  gfits_free_matrix (&buf[0].matrix);
+  gfits_free_header (&buf[0].header);
+  CreateBuffer (buf, Nx, Ny, -32, 0.0, 1.0);
+  strcpy (buf[0].file, "(empty)");
+
+  coords.crval1 = RaCenter;
+  coords.crval2 = DecCenter;
+  coords.crpix1 = 0.5*Nx;
+  coords.crpix2 = 0.5*Ny;
+  strcpy (coords.ctype, projection);
+  coords.pc1_1 = -1.0;
+  coords.pc2_2 = +1.0;
+  coords.pc1_2 =  0.0;
+  coords.pc2_1 =  0.0;
+  coords.cdelt1 = coords.cdelt2 = pixscale;
+  coords.Npolyterms = 0;
+
+  PutCoords (&coords, &buf[0].header);
+
+  V = (float *)buf[0].matrix.buffer;
+
+  for (ys = 0; ys < Ny; ys++) {
+    for (xs = 0; xs < Nx; xs++) {
+      status = XY_to_RD (&r, &d, (double)(xs), (double)(ys), &coords);
+      status &= (r >= 0);
+      status &= (r <= 360);
+      if (status) {
+	V[ys*Nx + xs] = ShowDensity ?  0 : 2;
+      } else {
+	V[ys*Nx + xs] = ShowDensity ? -1 : 0;
+      }
+    }
+  }
+
+  Nsecfilt = GetPhotcodeNsecfilt();
+  // grab data from all selected sky regions
+  Signal = signal (SIGINT, handle_interrupt);
+  interrupt = FALSE;
+
+  /* load region corresponding to selection above */
+  if ((skylist = SelectRegions (selection)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (k = 0; (k < skylist[0].Nregions) && !interrupt; k++) {
+    /* lock, load, unlock catalog */
+    catalog.filename = skylist[0].filename[k];
+    catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_SECF;
+    catalog.Nsecfilt = 0;
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, NULL, FALSE, "r")) {
+      fprintf (stderr, "ERROR: failure to open catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+    dvo_catalog_unlock (&catalog);
+
+    int Nsec = GetPhotcodeNsec(myCode);
+
+    for (j = 0; j <  catalog.Naverage; j++) {
+	if (catalog.average[j].Nmeasure < 2) { continue; }
+
+	
+	if (catalog.secfilt[j*Nsecfilt+Nsec].Ncode < 2) { continue; }
+
+	invalid = ((catalog.secfilt[j*Nsecfilt + Nsec].M < 1.0) || (isnan(catalog.secfilt[j*Nsecfilt + Nsec].M)));
+	if (invalid) continue;
+	
+	double r = catalog.average[j].R;
+	double d = catalog.average[j].D;
+	status = RD_to_XY (&Xs, &Ys, r, d, &coords);
+	if (Xs < 0) continue;
+	if (Ys < 0) continue;
+	if (Xs >= Nx) continue;
+	if (Ys >= Ny) continue;
+	if (status) {
+	    xs = (int)Xs;
+	    ys = (int)Ys;
+	    if (ShowDensity) {
+		V[ys*Nx + xs] += 1;
+	    } else {
+		V[ys*Nx + xs] = 1;
+	    }
+	}
+    }
+  }
+  return (TRUE);
+
+escape:
+  return (FALSE);
+}
+
+
Index: /branches/czw_branch/20110406/Ohana/src/photdbc/src/make_subcatalog.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/photdbc/src/make_subcatalog.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/photdbc/src/make_subcatalog.c	(revision 31606)
@@ -71,4 +71,9 @@
     }
 
+    // if the input catalog is an old type, generate the catID entries:
+    if (catalog[0].catformat < DVO_FORMAT_PS1_V1) {
+      subcatalog[0].average[Naverage].catID = catalog[0].catID;
+    }
+
     minMag   = 32;
     minSigma = 32;
@@ -127,4 +132,10 @@
       subcatalog[0].measure[Nmeasure]        = catalog[0].measure[offset];
       subcatalog[0].measure[Nmeasure].averef = Naverage;
+
+      // if the input catalog is an old type, generate the catID entries:
+      if (catalog[0].catformat < DVO_FORMAT_PS1_V1) {
+	subcatalog[0].measure[Nmeasure].catID = catalog[0].catID;
+      }
+
       Nmeasure ++;
       Nm ++;
Index: /branches/czw_branch/20110406/Ohana/src/relastro/src/UpdateObjects.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relastro/src/UpdateObjects.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relastro/src/UpdateObjects.c	(revision 31606)
@@ -189,5 +189,10 @@
       coords.crval1 = R[0];
       coords.crval2 = D[0];
-      Tmean /= (float) N;
+
+      if (FIT_TARGET == TARGET_HIGH_SPEED) {
+	  Tmean = 0.5*(Tmax - Tmin);
+      } else {
+	  Tmean /= (float) N;
+      }
       
       XVERB = FALSE && (catalog[i].measure[m].dM < 0.01) && (N == 6) && (mode == FIT_PM_ONLY);
Index: /branches/czw_branch/20110406/Ohana/src/relastro/src/high_speed_catalogs.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relastro/src/high_speed_catalogs.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relastro/src/high_speed_catalogs.c	(revision 31606)
@@ -10,5 +10,5 @@
 
   // load the current sky table (layout of all SkyRegions) 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, FALSE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
@@ -30,5 +30,5 @@
     catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
 
-    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "r")) {
       fprintf (stderr, "ERROR: failure reading catalog %s\n", catalog.filename);
       exit (1);
@@ -43,11 +43,6 @@
     high_speed_objects (skylist[0].regions[i], &catalog);
 
-    if (!UPDATE) {
-      dvo_catalog_unlock (&catalog);
-      dvo_catalog_free (&catalog);
-      continue;
-    }
-    
-    save_catalogs (&catalog, 1);
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
   }
   
Index: /branches/czw_branch/20110406/Ohana/src/relphot/doc/allsky.txt
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/doc/allsky.txt	(revision 31606)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/doc/allsky.txt	(revision 31606)
@@ -0,0 +1,50 @@
+
+2011.04.12
+
+  I have modified the code to operate on multiple filter at a time,
+  and to have a limited density, with the goal of running the analysis
+  on a huge area.  However, we are somewhat limited by the fact that the
+  'measure' and 'average' structures are huge and have far more than
+  is needed for just the relphot (or even relastro) analysis.  
+
+  I am exploring the idea of using a stripped-down structure in the
+  relphot analysis -- it would be assigned in bcatalog.
+
+  Here are the elements we actually need in relphot proper:
+
+average: 
+  FIELD R,              RA,          double,          RA,                           decimal degrees 
+  FIELD D,              DEC,         double,          DEC,                          decimal degrees 
+  FIELD Nmeasure,       NMEASURE,    unsigned short,  number of psf measurements
+  FIELD measureOffset,  OFF_MEASURE, int,             offset to first psf measurement
+  FIELD flags,          FLAGS,       uint32_t,        average object flags (star; ghost; etc)
+  = 2*8 + 2 + 4 + 4 = 26 bytes
+
+measure:
+  FIELD dR,             D_RA,         float,          RA offset,                	    arcsec
+  FIELD dD,             D_DEC,        float,          DEC offset,               	    arcsec
+  FIELD M,              MAG,          float,          catalog mag,       	       	    mag
+  FIELD Mcal,           M_CAL,        float,          image cal mag,	            mag
+
+  FIELD dM,             MAG_ERR,      float,          mag error,                      mag
+  FIELD airmass,        AIRMASS,      float,          (airmass - 1),		    airmass
+  FIELD Xccd,           X_CCD,        float,          X coord on chip,                pixels
+  FIELD Yccd,           Y_CCD,        float,          Y coord on chip,                pixels
+
+  FIELD t,              TIME,         int,   	      time in seconds (UNIX)
+  FIELD averef,         AVE_REF,      unsigned int,   reference to average entry      
+  FIELD imageID,        IMAGE_ID,     unsigned int,   reference to DVO image ID
+  FIELD dbFlags,        DB_FLAGS,     unsigned int,   flags supplied by analysis in database
+  FIELD photcode,       PHOTCODE,     unsigned short, photcode
+  = 8*4 + 4*4 + 2 = 50 bytes
+
+  (note that psfQual and photFlags are only used in bcatalog to select measurements)
+
+eg, 1 year 3 pi has 1 average and 20 measures per object (and 8 secfilt entries)
+
+* current: 112 + 8*24 + 20*148 = 3264 bytes / star
+* propose: 26  + 8*24 + 20*50  = 1218 bytes / star
+
+for the full 3pi area, in 30GB, we could use 820 stars per square
+degree (5740 per exposure), as opposed to the current limit of 300
+(2100 per exposure).
Index: /branches/czw_branch/20110406/Ohana/src/relphot/include/relphot.h
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/include/relphot.h	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/include/relphot.h	(revision 31606)
@@ -11,4 +11,5 @@
   unsigned int start;
   unsigned int stop;
+  short photcode;
   float Mcal;
   float dMcal;
@@ -85,9 +86,14 @@
 int    RELPHOT_GRID_BINNING;
 
-PhotCode      *photcode;
-int            PhotNsec;
-int            PhotSec;
+int      *photseclist;
+int      Nphotcodes;
+PhotCode **photcodes;
+// int            PhotSec;
+// int            PhotNsec;
 
 PhotCode      *refPhotcode;
+
+int MaxDensityUse;
+double MaxDensityValue;
 
 int AreaSelect;
@@ -213,7 +219,7 @@
 StatType      statsMosaicX        PROTO((Catalog *catalog));
 StatType      statsMosaicdM       PROTO((Catalog *catalog));
-StatType      statsStarN          PROTO((Catalog *catalog, int Ncatalog));
-StatType      statsStarS          PROTO((Catalog *catalog, int Ncatalog));
-StatType      statsStarX          PROTO((Catalog *catalog, int Ncatalog));
+StatType      statsStarN          PROTO((Catalog *catalog, int Ncatalog, int Nsec, int seccode));
+StatType      statsStarS          PROTO((Catalog *catalog, int Ncatalog, int Nsec));
+StatType      statsStarX          PROTO((Catalog *catalog, int Ncatalog, int Nsec));
 void          wcatalog            PROTO((Catalog *catalog));
 void          wimages             PROTO((void));
@@ -223,2 +229,10 @@
 void relphot_usage (void);
 void relphot_help (int argc, char **argv);
+
+off_t getImageByID (off_t ID);
+
+int rationalize_mosaics ();
+int LimitDensityCatalog (Catalog *subcatalog, Catalog *catalog);
+
+int populate_tiny_values (Catalog *catalog);
+int free_tiny_values (Catalog *catalog);
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/GridOps.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/GridOps.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/GridOps.c	(revision 31606)
@@ -348,4 +348,8 @@
   // sums for each star which touches as cell on both bases.
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+  int thisCode = photcodes[0][0].code;
+  int Nsec = GetPhotcodeNsec(thisCode);
+
   for (i = 0; i < Ngrid; i++) {
     
@@ -362,5 +366,5 @@
       mx = mlist[i][j];
       c  = clist[i][j];
-      n  = catalog[c].measure[mx].averef;
+      n  = catalog[c].measureT[mx].averef;
       
       // if we have already visited this star, skip the stuff below
@@ -369,5 +373,5 @@
 
       // skip stars marked as BAD
-      if (catalog[c].average[n].flags & STAR_BAD) {
+      if (catalog[c].secfilt[n*Nsecfilt+Nsec].flags & STAR_BAD) {
 	Nrel ++;
 	continue;
@@ -389,5 +393,5 @@
 
 	// skip measurements marked as BAD
-	if (catalog[c].measure[m].dbFlags & MEAS_BAD) {
+	if (catalog[c].measureT[m].dbFlags & MEAS_BAD) {
 	  Nbad ++;
 	  continue;
@@ -410,6 +414,5 @@
 	// select the color- and airmass-corrected observed magnitude for this star
 	// XXX need to be able to turn off the color-correction until initial average mags are found
-	// Msys = PhotSys (&catalog[c].measure[m], &catalog[c].average[n], &catalog[c].secfilt[n*PhotNsec]);
-	Msys = PhotCat (&catalog[c].measure[m]);
+	Msys = PhotCatTiny (&catalog[c].measureT[m]);
 	if (isnan(Msys)) {
 	  Nsys++;
@@ -418,5 +421,5 @@
 
 	// mag-error for this measurement
-	Merr =  MAX (catalog[c].measure[m].dM, MIN_ERROR);
+	Merr =  MAX (catalog[c].measureT[m].dM, MIN_ERROR);
 
 	// Wsys = 1.0 / SQ(Merr);
@@ -528,4 +531,6 @@
   if (!USE_GRID) return;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   Nmax = Nlist[0];
   for (i = 0; i < Ngrid; i++) {
@@ -545,5 +550,5 @@
       c = clist[i][j];
       
-      if (catalog[c].measure[m].dbFlags & MEAS_BAD) {
+      if (catalog[c].measureT[m].dbFlags & MEAS_BAD) {
 	Nbad ++;
 	continue;
@@ -565,6 +570,6 @@
       }
       
-      n = catalog[c].measure[m].averef;
-      Msys = PhotSys (&catalog[c].measure[m], &catalog[c].average[n], &catalog[c].secfilt[n*PhotNsec]);
+      n = catalog[c].measureT[m].averef;
+      Msys = PhotSysTiny (&catalog[c].measureT[m], &catalog[c].averageT[n], &catalog[c].secfilt[n*Nsecfilt]);
       if (isnan(Msys)) {
 	Nsys++;
@@ -572,5 +577,5 @@
       }
       list[N] = Msys - Mrel - Mcal - Mmos;
-      dlist[N] = MAX (catalog[c].measure[m].dM, MIN_ERROR);
+      dlist[N] = MAX (catalog[c].measureT[m].dM, MIN_ERROR);
       N++;
     }
@@ -613,4 +618,6 @@
   if (!USE_GRID) return;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   N = 0;
   for (i = 0; i < Ngrid; i++) 
@@ -630,5 +637,5 @@
       c = clist[i][j];
       
-      if (catalog[c].measure[m].dbFlags & MEAS_BAD) {
+      if (catalog[c].measureT[m].dbFlags & MEAS_BAD) {
 	Narea ++;
 	continue;
@@ -641,6 +648,6 @@
       if (isnan(Mrel)) continue;
 
-      n = catalog[c].measure[m].averef;
-      Msys = PhotSys (&catalog[c].measure[m], &catalog[c].average[n], &catalog[c].secfilt[n*PhotNsec]);
+      n = catalog[c].measureT[m].averef;
+      Msys = PhotSysTiny (&catalog[c].measureT[m], &catalog[c].averageT[n], &catalog[c].secfilt[n*Nsecfilt]);
 
       xlist[N] = Xmeas[c][m];
@@ -704,5 +711,5 @@
   gfits_create_matrix (&header, &matrix);
   gfits_modify (&header, "NEXTEND", OFF_T_FMT, 1,  Nimage + 3);
-  gfits_modify (&header, "FILTER", "%s", 1, photcode[0].name);
+  gfits_modify (&header, "FILTER", "%s", 1, photcodes[0][0].name);  // XXXX note that this expects a single photcode, enforced in initialize.d
   gfits_modify_alt (&header, "COMMENT", "%S", 1, "Mosaic Photometry Grid Analysis");
 
@@ -727,5 +734,5 @@
   theader.bitpix   = -32;
   gfits_create_Theader (&theader, "IMAGE");
-  gfits_modify (&theader, "FILTER", "%s", 1, photcode[0].name);
+  gfits_modify (&theader, "FILTER", "%s", 1, photcodes[0][0].name);
   gfits_modify (&theader, "EXTNAME", "%s", 1, "MAG_OFFSET");
   gfits_create_matrix  (&theader, &matrix);
@@ -742,5 +749,5 @@
   /* save grid Nmeas values */
   gfits_modify (&theader, "EXTNAME", "%s", 1, "NMEAS");
-  gfits_modify (&theader, "FILTER", "%s", 1, photcode[0].name);
+  gfits_modify (&theader, "FILTER", "%s", 1, photcodes[0][0].name);
   gfits_create_matrix  (&theader, &matrix);
   for (i = 0; i < gridX; i++) {
@@ -756,5 +763,5 @@
   /* save grid sigma values */
   gfits_modify (&theader, "EXTNAME", "%s", 1, "SIGMA");
-  gfits_modify (&theader, "FILTER", "%s", 1, photcode[0].name);
+  gfits_modify (&theader, "FILTER", "%s", 1, photcodes[0][0].name);
   gfits_create_matrix  (&theader, &matrix);
   for (i = 0; i < gridX; i++) {
@@ -776,5 +783,5 @@
 
     gfits_modify (&theader, "EXTNAME", "%s", 1, camera.ccdname[N]);
-    gfits_modify (&theader, "FILTER", "%s", 1, photcode[0].name);
+    gfits_modify (&theader, "FILTER", "%s", 1, photcodes[0][0].name);
     gfits_modify (&theader, "NX", "%d", 1, camera.Nx);
     gfits_modify (&theader, "NY", "%d", 1, camera.Ny);
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/ImageOps.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/ImageOps.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/ImageOps.c	(revision 31606)
@@ -1,5 +1,3 @@
 # include "relphot.h"
-
-# define USE_IMAGE_ID 1
 
 static off_t       **bin;     // link from catalog,measure to image	     
@@ -12,14 +10,7 @@
 static off_t        Nimage;   // number of available images
 
-// if we search by image ID, we sort (imageIDs, imageIdx) by imageIDs to get a sorted
-// index
-
-# if USE_IMAGE_ID
+// to search by image ID, we sort (imageIDs, imageIdx) by imageIDs to get a sorted index
 static off_t        *imageIDs; // list of all image IDs
 static off_t        *imageIdx; // list of index for image IDs 
-# else
-static unsigned int *start;
-static unsigned int *stop;
-# endif
 
 Image *getimages (off_t *N) {
@@ -40,5 +31,4 @@
   Nimage = N;
 
-# if USE_IMAGE_ID
   ALLOCATE (imageIDs, off_t, Nimage);
   ALLOCATE (imageIdx, off_t, Nimage);
@@ -49,13 +39,4 @@
   }
   llsortpair (imageIDs, imageIdx, Nimage);
-# else
-  ALLOCATE (start,   unsigned, Nimage);
-  ALLOCATE (stop,    unsigned, Nimage);
-
-  for (i = 0; i < Nimage; i++) {
-    start[i] = image[i].tzero - MAX(0.01*image[i].trate*image[i].NY, 1);
-    stop[i]  = image[i].tzero + MAX(1.01*image[i].trate*image[i].NY, 1);
-  }
-# endif
 }
 
@@ -65,5 +46,4 @@
   // use bisection to find the specified image ID
 
-# if USE_IMAGE_ID
   off_t Nlo, Nhi, N;
 
@@ -82,5 +62,4 @@
       return (imageIdx[N]);
   }
-# endif
 
   return (-1);
@@ -128,22 +107,29 @@
 }
 
-/* select all image equivalent to the current photcode */
+/* select all image equivalent to the active photcode set */
 void findImages (Catalog *catalog, int Ncatalog) {
 
   off_t j;
-  int i, ecode;
-
-  for (i = 0; i < Ncatalog; i++) {
+  int i, ecode, Ns, found;
+  
+  int Nmatch = 0;
+ for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Nmeasure; j++) {
-      ecode = GetPhotcodeEquivCodebyCode (catalog[i].measure[j].photcode);
-      if (photcode[0].code != ecode) continue;
+      ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[j].photcode);
+      found = FALSE;
+      for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	if (ecode == photcodes[Ns][0].code) found = TRUE;
+      }
+      if (!found) continue; 
       matchImage (catalog, j, i);
-    }
-  }
-}
-
-int findCCD (off_t idx, off_t meas, int cat, Measure *measure) {
-
-  int ccdnum;
+      Nmatch ++;
+    }
+  }
+ // fprintf (stderr, "matched %d detections to images\n", Nmatch);
+}
+
+int findCCD (off_t idx, off_t meas, int cat, MeasureTiny *measure) {
+
+  int ccdnum, found, Ns, ecode;
   double X, Y;
   char *pname, *filter, *p, base[256];
@@ -151,5 +137,14 @@
   /* identify the ccd on the basis of the photcode name */
   pname = GetPhotcodeNamebyCode (image[idx].photcode);
-  filter = photcode[0].name;
+
+  // XXX this seems quite terrible...
+  ecode = GetPhotcodeEquivCodebyCode (measure[0].photcode);
+  found = FALSE;
+  for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+    if (ecode == photcodes[Ns][0].code) found = TRUE;
+  }
+  if (!found) return (FALSE); 
+
+  filter = photcodes[Ns][0].name;
   sprintf (base, "%s.%s.", MOSAICNAME, filter);
   if (strncmp (pname, base, strlen (base))) return (FALSE);
@@ -170,7 +165,7 @@
 
   // old code to add this measurement to the grid cell for this chip 
-  // ave = measure[0].averef;
-  // ra  = catalog[cat].average[ave].R - measure[0].dR / 3600.0;
-  // dec = catalog[cat].average[ave].D - measure[0].dD / 3600.0;
+  // ave = measureT[0].averef;
+  // ra  = catalog[cat].averageT[ave].R - measureT[0].dR / 3600.0;
+  // dec = catalog[cat].averageT[ave].D - measureT[0].dD / 3600.0;
   // RD_to_XY (&X, &Y, ra, dec, &image[i].coords);
 
@@ -183,12 +178,11 @@
 }
 
-# if USE_IMAGE_ID
 void matchImage (Catalog *catalog, off_t meas, int cat) {
 
   off_t idx, ID;
   int status;
-  Measure *measure;
+  MeasureTiny *measure;
   
-  measure = &catalog[cat].measure[meas];
+  measure = &catalog[cat].measureT[meas];
 
   ID = measure[0].imageID;
@@ -226,45 +220,4 @@
 }
 
-# else
-// this is the time-based match
-void matchImage (Catalog *catalog, off_t meas, int cat) {
-
-  off_t i;
-  int status;
-  Measure *measure;
-  
-  measure = &catalog[cat].measure[meas];
-  for (i = 0; i < Nimage; i++) {
-    if (image[0].photcode == -1) continue;
-    if (measure[0].photcode != image[i].photcode) continue;
-    if (measure[0].t < start[i]) continue;
-    if (measure[0].t > stop[i]) continue;
-    
-    if (USE_GRID) {
-      status = findCCD(i, meas, cat);
-      if (!status) continue;
-    }
-
-    // index for (catalog, measure) -> image
-    bin[cat][meas] = i;
-
-    // index for image, Nentry -> catalog
-    clist[i][Nlist[i]] = cat;
-
-    // index for image, Nentry -> measure
-    mlist[i][Nlist[i]] = meas;
-    Nlist[i] ++;
-
-    if (Nlist[i] == NLIST[i]) {
-      NLIST[i] += 100;
-      REALLOCATE (clist[i], off_t, NLIST[i]);
-      REALLOCATE (mlist[i], off_t, NLIST[i]);
-    }	
-    return;
-  }
-  /*  fprintf (stderr, "can't find source image for this measurement: %d (%d)\n", measure[0].t, measure[0].photcode); */
-}
-# endif
-
 off_t getImageEntry (off_t meas, int cat) {
 
@@ -307,4 +260,6 @@
 
   if (FREEZE_IMAGES) return;
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
 
   if (PoorImages) {
@@ -339,5 +294,5 @@
       c = clist[i][j];
       
-      if (catalog[c].measure[m].dbFlags & MEAS_BAD) {
+      if (catalog[c].measureT[m].dbFlags & MEAS_BAD) {
 	  Nbad++;
 	  continue;
@@ -359,6 +314,6 @@
       }
       
-      n = catalog[c].measure[m].averef;
-      Msys = PhotSys (&catalog[c].measure[m], &catalog[c].average[n], &catalog[c].secfilt[n*PhotNsec]);
+      n = catalog[c].measureT[m].averef;
+      Msys = PhotSysTiny (&catalog[c].measureT[m], &catalog[c].averageT[n], &catalog[c].secfilt[n*Nsecfilt]);
       if (isnan(Msys)) {
 	Nsys++;
@@ -366,6 +321,6 @@
       }
       list[N] = Msys - Mrel - Mmos - Mgrid;
-      dlist[N] = MAX (catalog[c].measure[m].dM, MIN_ERROR);
-      if (catalog[c].measure[m].dM < IMFIT_SYS_SIGMA_LIM) {
+      dlist[N] = MAX (catalog[c].measureT[m].dM, MIN_ERROR);
+      if (catalog[c].measureT[m].dM < IMFIT_SYS_SIGMA_LIM) {
 	McalBright += list[N];
 	McalBright2 += SQ(list[N]);
@@ -632,3 +587,2 @@
   return (stats);
 }
-
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/MosaicOps.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/MosaicOps.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/MosaicOps.c	(revision 31606)
@@ -9,4 +9,7 @@
 static off_t   **imlist; /* mosaic -> image[] */
 static off_t   **bin;    /* catalog, measure -> mosaic */
+
+// list of mosaics associated with an image
+static off_t   *mosimage;
 
 // list of mosaic associated with each image  
@@ -33,4 +36,6 @@
   ALLOCATE (NIMLIST, off_t,   NMOSAIC);
 
+  ALLOCATE (mosimage, off_t, Nimage); // mosaic to which image belongs
+
   /* a 'mosaic' in relphot is (unlike relastro) a virtual concept: there is no 
    * entry in the image table that represents this mosaic.  Instead, it is an
@@ -40,4 +45,5 @@
   /* generate list of unique mosaics */
   for (i = 0; i < Nimage; i++) {
+    mosimage[i] = -1;
 
     /* select valid mosaic images by photcode */
@@ -56,4 +62,7 @@
       if (start > mosaic[j].stop)  continue;
       found = TRUE;
+
+      // add reference from image to mosaic
+      mosimage[i] = j;
 
       /* add image to mosaic image list */
@@ -77,4 +86,5 @@
     mosaic[Nmosaic].flags  = image[i].flags;
     mosaic[Nmosaic].secz  = image[i].secz;
+    mosaic[Nmosaic].photcode = GetPhotcodeEquivCodebyCode (image[i].photcode);
 
     /* add image to mosaic image list */
@@ -84,4 +94,7 @@
     imlist[Nmosaic][0] = i;
 
+    // add reference from image to mosaic
+    mosimage[i] = Nmosaic;
+    
     Nmosaic ++;
     if (Nmosaic == NMOSAIC) {
@@ -250,20 +263,27 @@
 int findMosaics (Catalog *catalog, int Ncatalog) {
   
-  int i, ecode;
+  int i, ecode, found, Ns;
   off_t j;
 
   if (!MOSAIC_ZEROPT) return (FALSE);
 
+  int Nmatch = 0;
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Nmeasure; j++) {
       if (TimeSelect) {
-	if (catalog[i].measure[j].t < TSTART) continue;
-	if (catalog[i].measure[j].t > TSTOP) continue;
-      }
-      ecode = GetPhotcodeEquivCodebyCode (catalog[i].measure[j].photcode);
-      if (photcode[0].code != ecode) continue;
+	if (catalog[i].measureT[j].t < TSTART) continue;
+	if (catalog[i].measureT[j].t > TSTOP) continue;
+      }
+      ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[j].photcode);
+      found = FALSE;
+      for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	if (ecode == photcodes[Ns][0].code) found = TRUE;
+      }
+      if (!found) continue;
       matchMosaics (catalog, j, i);
-    }
-  }
+      Nmatch ++;
+    }
+  }
+  // fprintf (stderr, "matched %d detections to mosaics\n", Nmatch);
   return (TRUE);
 }
@@ -271,36 +291,44 @@
 void matchMosaics (Catalog *catalog, off_t meas, int cat) {
 
-  int i;
-
-  for (i = 0; i < Nmosaic; i++) {
-    if (catalog[cat].measure[meas].t < mosaic[i].start) continue;
-    if (catalog[cat].measure[meas].t > mosaic[i].stop) continue;
+  off_t idx, ID, mosID;
+  MeasureTiny *measure;
+
+  measure = &catalog[cat].measureT[meas];
+
+  ID = measure[0].imageID;
+  idx = getImageByID (ID);
+  if (idx == -1) {
+    if (VERBOSE2) fprintf (stderr, "missed measurement "OFF_T_FMT", %d\n", meas, cat);
+    return;
+  }
+
+  mosID = mosimage[idx];
+  if (mosID < 0) {
+    Image *image = getimage(idx);
+    fprintf (stderr, "unmatched image %s\n", image[0].name);
+    return;
+  }
+
+  // test to check we got the right match:
+  {
+    Image *image = getimage(idx);
+    unsigned int imageStart = image[0].tzero - MAX(0.01*image[0].trate*image[0].NY, 1);
+    if (imageStart != mosaic[mosID].start) {
+      fprintf (stderr, "error in image to mosaic match\n");
+      abort();
+    }
+  }
+
+  bin[cat][meas] = mosID;
+
+  clist[mosID][Nlist[mosID]] = cat;
+  mlist[mosID][Nlist[mosID]] = meas;
+  Nlist[mosID] ++;
     
-# ifdef GRID_V1
-    if (USE_GRID) {
-      ave = catalog[cat].measure[meas].averef;
-      ra  = catalog[cat].average[ave].R - catalog[cat].measure[meas].dR / 3600.0;
-      dec = catalog[cat].average[ave].D - catalog[cat].measure[meas].dD / 3600.0;
-
-      /* X,Y always positive-definite in range 0,0 - dX, dY */
-      RD_to_XY (&X, &Y, ra, dec, &mosaic[i].coords);
-      setGridMeasure (meas, cat, X, Y);
-    }
-# endif
-
-    bin[cat][meas] = i;
-
-    clist[i][Nlist[i]] = cat;
-    mlist[i][Nlist[i]] = meas;
-    Nlist[i] ++;
-    
-    if (Nlist[i] == NLIST[i]) {
-      NLIST[i] += 100;
-      REALLOCATE (clist[i], int,   NLIST[i]);
-      REALLOCATE (mlist[i], off_t, NLIST[i]);
-    }	
-    return;
-  }
-  fprintf (stderr, "missed measurement\n");
+  if (Nlist[mosID] == NLIST[mosID]) {
+    NLIST[mosID] += 100;
+    REALLOCATE (clist[mosID], int,   NLIST[mosID]);
+    REALLOCATE (mlist[mosID], off_t, NLIST[mosID]);
+  }	
   return;
 }
@@ -324,5 +352,5 @@
 
   off_t i, j, m, c, N, Nmax;
-  int n, mark, bad, Nfew, Nbad, Ncal, Nrel, Ngrid, Nsys;
+  int n, mark, bad, Nfew, Nbad, Ncal, Nrel, Ngrid, Nsys, Nsecfilt;
   float Msys, Mrel, Mcal, Mgrid;
   double *list, *dlist, *Mlist, *dMlist;
@@ -334,4 +362,6 @@
 
   image = getimages (&N);
+
+  Nsecfilt = GetPhotcodeNsecfilt ();
 
   if (PoorImages) {
@@ -364,5 +394,5 @@
       c = clist[i][j];
       
-      if (catalog[c].measure[m].dbFlags & MEAS_BAD) {
+      if (catalog[c].measureT[m].dbFlags & MEAS_BAD) {
 	  Nbad ++;
 	  continue;
@@ -384,6 +414,6 @@
       }
       
-      n = catalog[c].measure[m].averef;
-      Msys = PhotSys (&catalog[c].measure[m], &catalog[c].average[n], &catalog[c].secfilt[n*PhotNsec]);
+      n = catalog[c].measureT[m].averef;
+      Msys = PhotSysTiny (&catalog[c].measureT[m], &catalog[c].averageT[n], &catalog[c].secfilt[n*Nsecfilt]);
       if (isnan(Msys)) {
 	Nsys++;
@@ -391,5 +421,5 @@
       }
       list[N]  = Msys - Mrel - Mcal - Mgrid;
-      dlist[N] = MAX (catalog[c].measure[m].dM, MIN_ERROR);
+      dlist[N] = MAX (catalog[c].measureT[m].dM, MIN_ERROR);
       Mlist[N] = Msys;
       dMlist[N] = list[N];
@@ -433,4 +463,198 @@
 }
   
+// When we rationalize the images/mosaics, we are driving the negative cloud images back
+// to 0.0.  At the same time, we make a guess to the effective impact on all other images,
+// driven by the coupling of common stars. 
+int rationalize_mosaics (Catalog *catalog, int Ncatalog) {
+
+  double *imageOffset, **starOffset;
+  int **starNcount, *seclist;
+  int **Slist, *NSlist, *NSLIST;
+  int i, j, k, m, nMos, Ns, found;
+
+  off_t Nimage;
+  Image *image;
+
+  // set a test value for now
+  float CLOUD_TOLERANCE = 0.025;
+
+  if (!MOSAIC_ZEROPT) return (FALSE);
+  if (FREEZE_MOSAICS) return (FALSE);
+
+  image = getimages (&Nimage);
+
+  ALLOCATE (imageOffset, double, Nmosaic);
+
+  ALLOCATE ( Slist, int *, Nmosaic); // array of calibrated star indexes on this mosaic
+  ALLOCATE (NSlist, int,   Nmosaic); // number of stars on mosaic
+  ALLOCATE (NSLIST, int,   Nmosaic); // number of Slist entries allocated
+  memset (Slist, 0, Nmosaic*sizeof(int *));
+
+  // find the images / mosaics with negative clouds and save their offset
+  for (i = 0; i < Nmosaic; i++) {
+  
+    NSlist[i] =   0;
+    NSLIST[i] = 100;
+    ALLOCATE (Slist[i], int, NSLIST[i]);
+
+    imageOffset[i] = 0.0;
+
+    if (VERBOSE2 && (fabs(mosaic[i].Mcal) < CLOUD_TOLERANCE)) {
+      fprintf (stderr, "cloud-free: %s : %f\n", image[imlist[i][0]].name, mosaic[i].Mcal);
+    } 
+    if (VERBOSE2 && (mosaic[i].Mcal < -CLOUD_TOLERANCE)) {
+      imageOffset[i] = -mosaic[i].Mcal; 
+      // NOTE the negative sign: down below, we are going to add in the negative of Mcal
+      // to this image, and the propagated mean values for other images
+      fprintf (stderr, "anti-clouds: %s : %f\n", image[imlist[i][0]].name, mosaic[i].Mcal);
+    } 
+    if (VERBOSE2 && (mosaic[i].Mcal > CLOUD_TOLERANCE)) {
+      fprintf (stderr, "cloudy    : %s : %f\n", image[imlist[i][0]].name, mosaic[i].Mcal);
+    } 
+  }
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+  ALLOCATE (seclist, int, Nphotcodes);
+  for (Ns = 0; Ns < Nphotcodes; Ns ++) { 
+    int thisCode = photcodes[Ns][0].code;
+    seclist[Ns] = GetPhotcodeNsec(thisCode);
+  }
+
+  // allocate an array for star offsets
+  int Nstars = 0;
+  int NSTARS = 1000;
+  ALLOCATE (starOffset, double *, NSTARS);
+  ALLOCATE (starNcount, int *,    NSTARS);
+  memset (starOffset, 0, NSTARS*sizeof(double *));
+  memset (starNcount, 0, NSTARS*sizeof(int *));
+
+  // find the mean offset for each star
+  for (i = 0; i < Ncatalog; i++) {
+    for (j = 0; j < catalog[i].Naverage; j++) {
+      ALLOCATE (starOffset[Nstars], double, Nphotcodes);
+      ALLOCATE (starNcount[Nstars], int,    Nphotcodes);
+      memset (starOffset[Nstars], 0, Nphotcodes*sizeof(double));
+      memset (starNcount[Nstars], 0, Nphotcodes*sizeof(int));
+      
+      m = catalog[i].averageT[j].measureOffset;
+
+      // determine the mosaic for each measurement
+      for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+
+	// skip unused measurements
+	if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue;
+
+	// skip unused measurements
+	int Nsec;
+	int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	found = FALSE;
+	for (Ns = 0; !found && (Ns < Nphotcodes); Ns ++) { 
+	  if (ecode == photcodes[Ns][0].code) {
+	    found = TRUE;
+	    break;
+	  }
+	}
+	if (!found) continue;
+	Nsec = seclist[Ns];
+
+	// bad stars for this secfilt
+	if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+
+	// skip REF measurements (not tied to an image)
+	if (getImageEntry (m, i) < 0) continue;
+
+	// find the source of this measurement (skip unassigned measurements)
+	nMos = bin[i][m];
+	if (nMos == -1) continue;
+
+	if (mosaic[nMos].photcode != ecode) {
+	  fprintf (stderr, "*");
+	}
+
+	assert (Ns >= 0);
+	assert (Ns < Nphotcodes);
+
+	// accumulate the offsets from the negative cloud images (others have 0.0 value)
+	starOffset[Nstars][Ns] += imageOffset[nMos];
+	starNcount[Nstars][Ns] ++;
+	
+	// record the mosaic->star reference
+	Slist[nMos][NSlist[nMos]] = Nstars;
+	NSlist[nMos] ++;
+	if (NSlist[nMos] == NSLIST[nMos]) {
+	  NSLIST[nMos] += 100;
+	  REALLOCATE (Slist[nMos], int, NSLIST[nMos]);
+	}	  
+      }
+      Nstars ++;
+      if (Nstars == NSTARS) {
+	NSTARS += 1000;
+	REALLOCATE (starOffset, double *, NSTARS);
+	REALLOCATE (starNcount, int *,    NSTARS);
+	memset (&starOffset[NSTARS-1000], 0, 1000*sizeof(double *));
+	memset (&starNcount[NSTARS-1000], 0, 1000*sizeof(int *));
+      }
+    }
+  }
+
+  // find the mean offset of the images without negative clouds
+  for (i = 0; i < Nmosaic; i++) {
+
+    found = FALSE;
+    for (Ns = 0; !found && (Ns < Nphotcodes); Ns ++) { 
+      if (mosaic[i].photcode == photcodes[Ns][0].code) {
+	found = TRUE;
+	break;
+      }
+    }
+    if (!found) {
+      fprintf (stderr, "invalid photcode for mosaic?\n");
+      abort();
+    }
+
+    // a negative cloud image (cloud: Mcal > 0; anti-clouds: Mcal < 0; imageOffset = -Mcal)
+    if (imageOffset[i] > 0.0) continue;
+
+    // we need to actually have cross-references to count
+    if (NSlist[i] < 2) continue;
+
+    float dM = 0.0;
+    for (j = 0; j < NSlist[i]; j++) {
+      Nstars = Slist[i][j];
+      if (starNcount[Nstars][Ns] > 1) {
+	dM += (starOffset[Nstars][Ns] / starNcount[Nstars][Ns]);
+      }
+    }
+    imageOffset[i] = dM / NSlist[i];
+    // fprintf (stderr, "adjust image: %s : (%f %d) : %f\n", image[imlist[i][0]].name, dM, NSlist[i], imageOffset[i]);
+  }
+
+  // for (i = 0; i < Nmosaic; i++) {
+  //   fprintf (stderr, "correction: %s : %f\n", image[imlist[i][0]].name, imageOffset[i]);
+  // } 
+
+  // apply all offset values to the mosaics
+  // find the images / mosaics with negative clouds and save their offset
+  for (i = 0; i < Nmosaic; i++) {
+    mosaic[i].Mcal += imageOffset[i];
+  }
+
+  for (i = 0; i < Nstars; i++) {
+    free (starOffset[i]);
+    free (starNcount[i]);
+  }
+  free (starOffset);
+  free (starNcount);
+
+  for (i = 0; i < Nmosaic; i++){
+    free (Slist[i]);
+  }
+  free (NSlist);
+  free (NSLIST);
+  free (imageOffset);
+  free (seclist);
+  return (TRUE);
+}
+
 StatType statsMosaicM (Catalog *catalog) {
 
@@ -524,5 +748,5 @@
     n++;
   }
-  fprintf (stderr, "Nmosaic: "OFF_T_FMT", n: "OFF_T_FMT"\n",  Nmosaic,  n);
+  // fprintf (stderr, "Nmosaic: "OFF_T_FMT", n: "OFF_T_FMT"\n",  Nmosaic,  n);
 
   liststats (list, dlist, n, &stats);
@@ -563,5 +787,5 @@
 void clean_mosaics () {
 
-  off_t i, N, mark, Nmark;
+  off_t i, N, mark, Nmark, Nscatter, Noffset;
   double *mlist, *slist, *dlist;
   double MaxOffset, MedOffset, MaxScatter;
@@ -592,8 +816,15 @@
   fprintf (stderr, "Mrel: %f, dMrel: %f, Max Scatter: %f, Max Offset: %f\n", MedOffset, stats.median, MaxScatter, MaxOffset);
   
-  Nmark = 0;
+  Nmark = Nscatter = Noffset = 0;
   for (i = 0; i < Nmosaic; i++) {
     mark = FALSE;
-    mark = (mosaic[i].dMcal > MaxScatter) || (fabs(mosaic[i].Mcal - MedOffset) > MaxOffset);
+    if (mosaic[i].dMcal > MaxScatter) {
+      mark = TRUE;
+      Nscatter ++;
+    }
+    if (fabs(mosaic[i].Mcal - MedOffset) > MaxOffset) {
+      mark = TRUE;
+      Noffset ++;
+    }
     if (mark) { 
       Nmark ++;
@@ -604,5 +835,5 @@
   }
 
-  fprintf (stderr, OFF_T_FMT" mosaics marked poor\n",  Nmark);
+  fprintf (stderr, OFF_T_FMT" mosaics marked poor ("OFF_T_FMT" scatter, "OFF_T_FMT" offset)\n",  Nmark, Nscatter, Noffset);
   initstats (STATMODE);
   free (mlist);
@@ -640,9 +871,9 @@
       c = clist[i][j];
       
-      if (catalog[c].measure[m].dbFlags & (ID_MEAS_AREA | ID_MEAS_NOCAL)) continue;
-
-      ave = catalog[c].measure[m].averef;
-      xlist[N] = catalog[c].average[ave].R - catalog[c].measure[m].dR / 3600.0;
-      ylist[N] = catalog[c].average[ave].D - catalog[c].measure[m].dD / 3600.0;
+      if (catalog[c].measureT[m].dbFlags & (ID_MEAS_AREA | ID_MEAS_NOCAL)) continue;
+
+      ave = catalog[c].measureT[m].averef;
+      xlist[N] = catalog[c].averageT[ave].R - catalog[c].measureT[m].dR / 3600.0;
+      ylist[N] = catalog[c].averageT[ave].D - catalog[c].measureT[m].dD / 3600.0;
       N++;
     }
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/StarOps.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/StarOps.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/StarOps.c	(revision 31606)
@@ -5,4 +5,10 @@
 static double *dlist;
 
+// When we rationalize the images/mosaics, we are driving the negative cloud images back
+// to 0.0.  At the same time, we make a guess to the effective impact on all other images,
+// driven by the coupling of common stars.  This array carries the impact of those offsets
+// on each star
+static double *Moffset;
+
 void initMrel (Catalog *catalog, int Ncatalog) {
 
@@ -12,21 +18,30 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-      Nmax = MAX (Nmax, catalog[i].average[j].Nmeasure);
-    }
-  }
-
-  ALLOCATE (list, double, MAX (1, Nmax));
-  ALLOCATE (dlist, double, MAX (1, Nmax));
+      Nmax = MAX (Nmax, catalog[i].averageT[j].Nmeasure);
+    }
+  }
+
+  ALLOCATE (list,    double, MAX (1, Nmax));
+  ALLOCATE (dlist,   double, MAX (1, Nmax));
+  ALLOCATE (Moffset, double, MAX (1, Nmax));
 }  
 
 float getMrel (Catalog *catalog, off_t meas, int cat) {
 
+  int Nsec, Nsecfilt, photcode;
   int ave;
   float value;
 
-  ave = catalog[cat].measure[meas].averef;
-  if (catalog[cat].average[ave].flags & STAR_BAD) return (NAN);  
+  ave = catalog[cat].measureT[meas].averef;
+  photcode = catalog[cat].measureT[meas].photcode;
+
+  int ecode = GetPhotcodeEquivCodebyCode (photcode);
+  Nsec = GetPhotcodeNsec(ecode);
+  Nsecfilt = GetPhotcodeNsecfilt ();
+
+  // is this star OK?
+  if (catalog[cat].secfilt[Nsecfilt*ave+Nsec].flags & STAR_BAD) return (NAN);  
  
-  value = catalog[cat].secfilt[PhotNsec*ave+PhotSec].M;
+  value = catalog[cat].secfilt[Nsecfilt*ave+Nsec].M;
   return (value);
 }
@@ -39,4 +54,5 @@
   StatType stats;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
   Nfew = Nsys = Nbad = Ncal = Nmos = Ngrid = 0;
 
@@ -44,68 +60,81 @@
     for (j = 0; j < catalog[i].Naverage; j++) {
 
-      /* calculate the average value for a single star */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-      m = catalog[i].average[j].measureOffset;
-
-      N = 0;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	if (catalog[i].measure[m].dbFlags & MEAS_BAD) {
-	  Nbad ++;
-	  continue;
-	}
-	// XXX allow REF stars (no Image Entry) to be included in the calculation this
-	// should be optionally set, and should allow for REF stars to be downweighted by
-	// more than their reported errors.  how such info is carried is unclear...
-	if (getImageEntry (m, i) < 0) {
-	  Mcal = Mmos = Mgrid = 0;
-	} else {
-	  Mcal  = getMcal  (m, i);
-	  if (isnan(Mcal)) { 
-	    Ncal ++;
+      int Ns;
+      for (Ns = 0; Ns < Nphotcodes; Ns++) {
+
+	int thisCode = photcodes[Ns][0].code;
+	int Nsec = GetPhotcodeNsec(thisCode);
+
+	/* calculate the average value for a single star */
+
+	// skip bad stars
+	if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;
+	m = catalog[i].averageT[j].measureOffset;
+
+	N = 0;
+	for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	  // skip measurements that do not match the current photcode
+	  int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	  if (ecode != thisCode) { continue; }
+
+	  if (catalog[i].measureT[m].dbFlags & MEAS_BAD) {
+	    Nbad ++;
 	    continue;
 	  }
-	  Mmos  = getMmos  (m, i);
-	  if (isnan(Mmos)) {
-	    Nmos ++;
+	  // XXX allow REF stars (no Image Entry) to be included in the calculation this
+	  // should be optionally set, and should allow for REF stars to be downweighted by
+	  // more than their reported errors.  how such info is carried is unclear...
+	  if (getImageEntry (m, i) < 0) {
+	    Mcal = Mmos = Mgrid = 0;
+	  } else {
+	    Mcal  = getMcal  (m, i);
+	    if (isnan(Mcal)) { 
+	      Ncal ++;
+	      continue;
+	    }
+	    Mmos  = getMmos  (m, i);
+	    if (isnan(Mmos)) {
+	      Nmos ++;
+	      continue;
+	    }
+	    Mgrid = getMgrid (m, i);
+	    if (isnan(Mgrid)) {
+	      Ngrid++;
+	      continue;
+	    }
+	  }
+
+	  Msys = PhotSysTiny (&catalog[i].measureT[m], &catalog[i].averageT[j], &catalog[i].secfilt[j*Nsecfilt]);
+	  if (isnan(Msys)) {
+	    Nsys++;
 	    continue;
 	  }
-	  Mgrid = getMgrid (m, i);
-	  if (isnan(Mgrid)) {
-	    Ngrid++;
-	    continue;
+	  list[N] = Msys - Mcal - Mmos - Mgrid;
+	  dlist[N] = MAX (catalog[i].measureT[m].dM, MIN_ERROR);
+
+	  // tie down reference photometry if the -refcode (code) option is selected
+	  if (refPhotcode) {
+	    if (GetPhotcodeEquivCodebyCode(catalog[i].measureT[m].photcode) == refPhotcode[0].equiv) {
+	      // increase the weight by a factor of 100:
+	      dlist[N] = 0.01*catalog[i].measureT[m].dM;
+	    }
 	  }
-	}
-
-	Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]);
-	if (isnan(Msys)) {
-	  Nsys++;
-	  continue;
-	}
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-	dlist[N] = MAX (catalog[i].measure[m].dM, MIN_ERROR);
-
-	if (refPhotcode) {
-	  if (GetPhotcodeEquivCodebyCode(catalog[i].measure[m].photcode) == refPhotcode[0].equiv) {
-	    // increase the weight by a factor of 100:
-	    dlist[N] = 0.01*catalog[i].measure[m].dM;
-	  }
-	}
-	N++;
-      }
-
-      // when performing the grid analysis, STAR_TOOFEW will be set to 1;
-
-      if (N <= STAR_TOOFEW) { /* too few measurements */
-	catalog[i].average[j].flags |= ID_STAR_FEW;
-	Nfew ++;
-      } else {
-	catalog[i].average[j].flags &= ~ID_STAR_FEW;
-      }	
-
-      liststats (list, dlist, N, &stats);
-
-      catalog[i].secfilt[PhotNsec*j+PhotSec].M  = stats.mean;
-      catalog[i].secfilt[PhotNsec*j+PhotSec].dM = stats.sigma;
-      catalog[i].secfilt[PhotNsec*j+PhotSec].Xm = (stats.Nmeas > 1) ? 100.0*log10(stats.chisq) : NAN_S_SHORT;
+	  N++;
+	}
+
+	// when performing the grid analysis, STAR_TOOFEW will be set to 1;
+	if (N <= STAR_TOOFEW) { /* too few measurements */
+	  catalog[i].secfilt[Nsecfilt*j+Nsec].flags |= ID_STAR_FEW;
+	  Nfew ++;
+	} else {
+	  catalog[i].secfilt[Nsecfilt*j+Nsec].flags &= ~ID_STAR_FEW;
+	}	
+
+	liststats (list, dlist, N, &stats);
+
+	catalog[i].secfilt[Nsecfilt*j+Nsec].M  = stats.mean;
+	catalog[i].secfilt[Nsecfilt*j+Nsec].dM = stats.sigma;
+	catalog[i].secfilt[Nsecfilt*j+Nsec].Xm = (stats.Nmeas > 1) ? 100.0*log10(stats.chisq) : NAN_S_SHORT;
+      }
     }
   }
@@ -122,4 +151,7 @@
   double *list, *dlist;
   StatType stats;
+  int Nsec, Nsecfilt, ecode;
+
+  Nsecfilt = GetPhotcodeNsecfilt ();
 
   /* Nmeasure is now different, need to reallocate */
@@ -127,5 +159,5 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-      Nmax = MAX (Nmax, catalog[i].average[j].Nmeasure);
+      Nmax = MAX (Nmax, catalog[i].averageT[j].Nmeasure);
     }
   }
@@ -135,40 +167,50 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-
       /* skip stars already calibrated */
       if (catalog[i].found[j]) continue;  
 
-      N = 0;
-      m = catalog[i].average[j].measureOffset;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	if (catalog[i].measure[m].dbFlags & MEAS_BAD) continue;
-	// XXX allow REF stars (no Image Entry) to be included in the calculation this
-	// should be optionally set, and should allow for REF stars to be downweighted by
-	// more than their reported errors.  how such info is carried is unclear...
-	if (getImageEntry (m, i) < 0) {
-	  Mcal = Mmos = Mgrid = 0;
-	} else {
-	  Mcal  = getMcal  (m, i);
-	  if (isnan(Mcal)) continue;
-	  Mmos  = getMmos  (m, i);
-	  if (isnan(Mmos)) continue;
-	  Mgrid = getMgrid (m, i);
-	  if (isnan(Mgrid)) continue;
-	}
-
-	Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]);
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-	dlist[N] = MAX (catalog[i].measure[m].dM, MIN_ERROR);
-	N++;
-      }
-      if (N < 1) continue;
-
-      liststats (list, dlist, N, &stats);
-      if (mark) catalog[i].found[j] = TRUE;
-
-      /* use sigma or error in dM for output? */
-      catalog[i].secfilt[PhotNsec*j+PhotSec].M  = stats.mean;
-      catalog[i].secfilt[PhotNsec*j+PhotSec].dM = MAX (stats.error, stats.sigma);
-      catalog[i].secfilt[PhotNsec*j+PhotSec].Xm = (stats.Nmeas > 1) ? 100.0*log10(stats.chisq) : NAN_S_SHORT;
+      int Ns;
+      for (Ns = 0; Ns < Nphotcodes; Ns++) {
+	int thisCode = photcodes[Ns][0].code;
+	Nsec = GetPhotcodeNsec(thisCode);
+
+	N = 0;
+	m = catalog[i].averageT[j].measureOffset;
+	for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	  // skip measurements that do not match the current photcode
+	  ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	  if (ecode != thisCode) { continue; }
+
+	  if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue;
+
+	  // XXX allow REF stars (no Image Entry) to be included in the calculation this
+	  // should be optionally set, and should allow for REF stars to be downweighted by
+	  // more than their reported errors.  how such info is carried is unclear...
+	  if (getImageEntry (m, i) < 0) {
+	    Mcal = Mmos = Mgrid = 0;
+	  } else {
+	    Mcal  = getMcal  (m, i);
+	    if (isnan(Mcal)) continue;
+	    Mmos  = getMmos  (m, i);
+	    if (isnan(Mmos)) continue;
+	    Mgrid = getMgrid (m, i);
+	    if (isnan(Mgrid)) continue;
+	  }
+
+	  Msys = PhotSysTiny (&catalog[i].measureT[m], &catalog[i].averageT[j], &catalog[i].secfilt[j*Nsecfilt]);
+	  list[N] = Msys - Mcal - Mmos - Mgrid;
+	  dlist[N] = MAX (catalog[i].measureT[m].dM, MIN_ERROR);
+	  N++;
+	}
+	if (N < 1) continue;
+
+	liststats (list, dlist, N, &stats);
+	if (mark) catalog[i].found[j] = TRUE;
+
+	/* use sigma or error in dM for output? */
+	catalog[i].secfilt[Nsecfilt*j+Nsec].M  = stats.mean;
+	catalog[i].secfilt[Nsecfilt*j+Nsec].dM = MAX (stats.error, stats.sigma);
+	catalog[i].secfilt[Nsecfilt*j+Nsec].Xm = (stats.Nmeas > 1) ? 100.0*log10(stats.chisq) : NAN_S_SHORT;
+      }
     }
   }
@@ -179,5 +221,7 @@
 }
 
-// for each average object, set the average mags based on existing equiv photometry
+// For each average object, set the average mags based on existing equiv photometry.
+// NOTE: this function operates on the real Measure & Average structures, not the
+// MeasureTiny & AverageTiny structures
 int setMave (Catalog *catalog, int Ncatalog) {
 
@@ -202,5 +246,5 @@
   ALLOCATE (dlist, double, MAX (1, Nmax));
 
-  Nsecfilt = catalog[0].Nsecfilt;
+  Nsecfilt = GetPhotcodeNsecfilt ();
 
 # define PSFQUALSTATS 1
@@ -220,5 +264,5 @@
 	  if (GetPhotcodeEquivCodebyCode (catalog[i].measure[m].photcode) != Nc) continue;
 
-	  Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]);
+	  Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
 	  if (isnan(Msys)) continue;
 
@@ -321,7 +365,7 @@
     for (j = 0; j < catalog[i].Naverage; j++) {
 
-      m = catalog[i].average[j].measureOffset;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	if (catalog[i].measure[m].dbFlags & MEAS_BAD) continue;
+      m = catalog[i].averageT[j].measureOffset;
+      for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue;
 	Mcal  = getMcal  (m, i);
 	if (isnan(Mcal)) continue;
@@ -330,4 +374,6 @@
 	Mgrid = getMgrid (m, i);
 	if (isnan(Mgrid)) continue;
+
+	// set the output calibration
 	catalog[i].measure[m].Mcal = Mcal + Mmos + Mgrid;
       }
@@ -339,5 +385,5 @@
 void clean_stars (Catalog *catalog, int Ncatalog) {
 
-  int i, j, Ndel, Nave, Ntot, mark;
+  int i, j, Ndel, Nave, Ntot, mark, Ns;
   float dM, Xm;
   double Chisq, MaxScatter, MaxChisq;
@@ -354,42 +400,53 @@
   ALLOCATE (slist, double, Ntot);
   ALLOCATE (dlist, double, Ntot);
-  for (i = Ntot = 0; i < Ncatalog; i++) {
-    for (j = 0; j < catalog[i].Naverage; j++) {
-      if (catalog[i].average[j].flags & STAR_BAD) continue;
-      Xm = catalog[i].secfilt[PhotNsec*j+PhotSec].Xm;
-      if (Xm == -1) continue;
-      Chisq = pow (10.0, 0.01*Xm);
-      xlist[Ntot] = Chisq;
-      slist[Ntot] = catalog[i].secfilt[PhotNsec*j+PhotSec].dM;
-      dlist[Ntot] = 1;
-      Ntot ++;
-    }
-  }
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  // eliminate bad stars using the stats for a single secfilt at a time
+  // XXX DEP replace average.flags with secfilt flags
+  for (Ns = 0; Ns < Nphotcodes; Ns ++) {
+    
+    int thisCode = photcodes[Ns][0].code;
+    int Nsec = GetPhotcodeNsec(thisCode);
+
+    for (i = Ntot = 0; i < Ncatalog; i++) {
+      for (j = 0; j < catalog[i].Naverage; j++) {
+	if ( catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD ) continue;
+	Xm = catalog[i].secfilt[Nsecfilt*j+Nsec].Xm;
+	if (Xm == -1) continue;
+	Chisq = pow (10.0, 0.01*Xm);
+	xlist[Ntot] = Chisq;
+	slist[Ntot] = catalog[i].secfilt[Nsecfilt*j+Nsec].dM;
+	dlist[Ntot] = 1;
+	Ntot ++;
+      }
+    }
   
-  initstats ("MEAN");
-  liststats (xlist, dlist, Ntot, &stats);
-  MaxChisq = MAX (STAR_CHISQ, 2*stats.median);
-  liststats (slist, dlist, Ntot, &stats);
-  MaxScatter = MAX (STAR_SCATTER, 2*stats.median);
-  fprintf (stderr, "Max Scatter: %f, Max Chisq: %f\n", MaxScatter, MaxChisq);
-
-  Ndel = Nave = 0;
-  for (i = 0; i < Ncatalog; i++) {
-    for (j = 0; j < catalog[i].Naverage; j++) {
-      dM = catalog[i].secfilt[PhotNsec*j+PhotSec].dM;
-      Xm = catalog[i].secfilt[PhotNsec*j+PhotSec].Xm;
-      Chisq = pow (10.0, 0.01*Xm);
-      mark = (dM > MaxScatter) || (Xm == NAN_S_SHORT) || (Chisq > MaxChisq);
-      if (mark) {
-	catalog[i].average[j].flags |= ID_STAR_POOR;
-	Ndel ++;
-      } else {
-	catalog[i].average[j].flags &= ~ID_STAR_POOR;
-      }
-      Nave ++;
-    }
-  }
-  fprintf (stderr, "%d stars marked variable, %d total\n", Ndel, Nave);
-  initstats (STATMODE);
+    initstats ("MEAN");
+    liststats (xlist, dlist, Ntot, &stats);
+    MaxChisq = MAX (STAR_CHISQ, 2*stats.median);
+    liststats (slist, dlist, Ntot, &stats);
+    MaxScatter = MAX (STAR_SCATTER, 2*stats.median);
+    fprintf (stderr, "Max Scatter: %f, Max Chisq: %f\n", MaxScatter, MaxChisq);
+
+    Ndel = Nave = 0;
+    for (i = 0; i < Ncatalog; i++) {
+      for (j = 0; j < catalog[i].Naverage; j++) {
+	dM = catalog[i].secfilt[Nsecfilt*j+Nsec].dM;
+	Xm = catalog[i].secfilt[Nsecfilt*j+Nsec].Xm;
+	Chisq = pow (10.0, 0.01*Xm);
+	mark = (dM > MaxScatter) || (Xm == NAN_S_SHORT) || (Chisq > MaxChisq);
+	if (mark) {
+	  catalog[i].secfilt[Nsecfilt*j+Nsec].flags |= ID_STAR_POOR;
+	  Ndel ++;
+	} else {
+	  catalog[i].secfilt[Nsecfilt*j+Nsec].flags &= ~ID_STAR_POOR;
+	}
+	Nave ++;
+      }
+    }
+    fprintf (stderr, "%d stars marked variable, %d total\n", Ndel, Nave);
+    initstats (STATMODE);
+  }
   free (xlist);
   free (slist);
@@ -409,4 +466,6 @@
   int Ncal, Nmos, Ngrid, Nfew;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   if (VERBOSE) fprintf (stderr, "marking poor measures\n");
   /* Nmeasure is now different, need to reallocate */
@@ -414,5 +473,5 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-      Nmax = MAX (Nmax, catalog[i].average[j].Nmeasure);
+      Nmax = MAX (Nmax, catalog[i].averageT[j].Nmeasure);
     }
   }
@@ -430,79 +489,98 @@
     for (j = 0; j < catalog[i].Naverage; j++) {
 
-      /* skip bad stars to prevent them from becoming good (on inner sample) */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-
-      /* on final processing, skip stars already measured */
-      if (final && catalog[i].found[j]) continue;  
-
-      /* accumulate list of valid measurements */
-      m = catalog[i].average[j].measureOffset;
-      N = 0;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	/* if (catalog[i].measure[m].dbFlags & MEAS_BAD) continue; */
-	Mcal  = getMcal  (m, i);
-	if (isnan(Mcal)) { Ncal ++; continue; }
-	Mmos  = getMmos  (m, i);
-	if (isnan(Mmos)) { Nmos ++; continue; }
-	Mgrid = getMgrid (m, i);
-	if (isnan(Mgrid)) { Ngrid ++; continue; }
-
-	Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]);
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-	dlist[N] = MAX (catalog[i].measure[m].dM, MIN_ERROR);
-	N++;
-      }
-      if (N <= TOOFEW) { Nfew ++; continue; }
-
-      /* 3-sigma clip based on stats of inner 50% */
-
-      // calculated mean of inner 50%
-      initstats ("INNER_MEAN");
-      liststats (list, dlist, N, &stats);
-      stats.sigma = MAX (MIN_ERROR, stats.sigma); /* if measurements agree too well, sigma -> 0.0 */
-
-      // ignore entries > 3sigma from inner mean
-      for (k = m = 0; k < N; k++) {
-	if (fabs (list[k] - stats.median) < NSIGMA_CLIP*stats.sigma) {
-	  list[m] = list[k];
-	  m++;
-	}
-      }
-      // recalculate the mean & sigma of the accepted measurements
-      initstats ("MEAN");
-      liststats (list, dlist, m, &stats);
-      stats.sigma = MAX (MIN_ERROR, stats.sigma);
-
-      /* apply to list of all relevant measurements, including IMAGE_POOR & IMAGE_FEW */
-      image_bad = IMAGE_BAD;
-      IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL;
-      m = catalog[i].average[j].measureOffset;
-      N = 0;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	/* if (catalog[i].measure[m].dbFlags & MEAS_BAD) continue; */
-	Mcal  = getMcal  (m, i);
-	if (isnan(Mcal)) continue;
-	Mmos  = getMmos  (m, i);
-	if (isnan(Mmos)) continue;
-	Mgrid = getMgrid (m, i);
-	if (isnan(Mgrid)) continue;
-
-	Msys = PhotSys (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]);
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-	dlist[N] = MAX (catalog[i].measure[m].dM, MIN_ERROR);
-	ilist[N] = m;
-	N++;
-	Nave ++;
-      }
-      if (N < TOOFEW) continue;
-
-      /* mark bad measures (> 3 sigma deviant) */
-      for (k = 0; k < N; k++) {
-	if (fabs (list[k] - stats.median) > NSIGMA_REJECT*stats.sigma) {
-	  catalog[i].measure[ilist[k]].dbFlags |= ID_MEAS_POOR_PHOTOM;
-	  Ndel ++;
-	}
-      }
-      IMAGE_BAD = image_bad;
+      int Ns;
+      for (Ns = 0; Ns < Nphotcodes; Ns++) {
+	
+	/* on final processing, skip stars already measured */
+	if (final && catalog[i].found[j]) continue;  
+
+	int thisCode = photcodes[Ns][0].code;
+	int Nsec = GetPhotcodeNsec(thisCode);
+	
+	/* skip bad stars to prevent them from becoming good (on inner sample) */
+	if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+
+	/* accumulate list of valid measurements */
+	m = catalog[i].averageT[j].measureOffset;
+	N = 0;
+	for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	  // skip measurements that do not match the current photcode
+	  int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	  if (ecode != thisCode) { continue; }
+
+	  /* if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue; */
+	  Mcal  = getMcal  (m, i);
+	  if (isnan(Mcal)) { Ncal ++; continue; }
+	  Mmos  = getMmos  (m, i);
+	  if (isnan(Mmos)) { Nmos ++; continue; }
+	  Mgrid = getMgrid (m, i);
+	  if (isnan(Mgrid)) { Ngrid ++; continue; }
+
+	  Msys = PhotSysTiny (&catalog[i].measureT[m], &catalog[i].averageT[j], &catalog[i].secfilt[j*Nsecfilt]);
+	  list[N] = Msys - Mcal - Mmos - Mgrid;
+	  dlist[N] = MAX (catalog[i].measureT[m].dM, MIN_ERROR);
+	  N++;
+	}
+	if (N <= TOOFEW) { Nfew ++; continue; }
+
+	/* 3-sigma clip based on stats of inner 50% */
+
+	// calculated mean of inner 50%
+	initstats ("INNER_MEAN");
+	liststats (list, dlist, N, &stats);
+	stats.sigma = MAX (MIN_ERROR, stats.sigma); /* if measurements agree too well, sigma -> 0.0 */
+
+	// ignore entries > 3sigma from inner mean
+	for (k = m = 0; k < N; k++) {
+	  if (fabs (list[k] - stats.median) < NSIGMA_CLIP*stats.sigma) {
+	    list[m] = list[k];
+	    m++;
+	  }
+	}
+	// recalculate the mean & sigma of the accepted measurements
+	initstats ("MEAN");
+	liststats (list, dlist, m, &stats);
+	stats.sigma = MAX (MIN_ERROR, stats.sigma);
+
+	/* apply to list of all relevant measurements, including IMAGE_POOR & IMAGE_FEW */
+	image_bad = IMAGE_BAD;
+	IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL;
+	m = catalog[i].averageT[j].measureOffset;
+	N = 0;
+	for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	  // skip measurements that do not match the current photcode
+	  int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	  if (ecode != thisCode) { continue; }
+
+	  /* if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue; */
+	  Mcal  = getMcal  (m, i);
+	  if (isnan(Mcal)) continue;
+	  Mmos  = getMmos  (m, i);
+	  if (isnan(Mmos)) continue;
+	  Mgrid = getMgrid (m, i);
+	  if (isnan(Mgrid)) continue;
+
+	  Msys = PhotSysTiny (&catalog[i].measureT[m], &catalog[i].averageT[j], &catalog[i].secfilt[j*Nsecfilt]);
+	  list[N] = Msys - Mcal - Mmos - Mgrid;
+	  dlist[N] = MAX (catalog[i].measureT[m].dM, MIN_ERROR);
+	  ilist[N] = m;
+	  N++;
+	  Nave ++;
+	}
+	if (N < TOOFEW) continue;
+
+	/* mark bad measures (> 3 sigma deviant) */
+	for (k = 0; k < N; k++) {
+	  if (fabs (list[k] - stats.median) > NSIGMA_REJECT*stats.sigma) {
+	    catalog[i].measureT[ilist[k]].dbFlags |= ID_MEAS_POOR_PHOTOM;
+	    if (final) {
+	      // for the final pass, we have a duplicate set of values in measure and measureT
+	      catalog[i].measure[ilist[k]].dbFlags |= ID_MEAS_POOR_PHOTOM;
+	    }
+	    Ndel ++;
+	  }
+	}
+	IMAGE_BAD = image_bad;
+      }
     }
   }
@@ -513,5 +591,5 @@
 }
 
-StatType statsStarN (Catalog *catalog, int Ncatalog) {
+StatType statsStarN (Catalog *catalog, int Ncatalog, int Nsec, int seccode) {
 
   off_t j, k, m, Ntot;
@@ -520,4 +598,8 @@
   float Mcal, Mmos, Mgrid;
   StatType stats;
+  // int N1, N2, N3, N4, N0;
+  // N1 = N2 = N3 = N4 = N0 = 0;
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
 
   Ntot = 0;
@@ -534,15 +616,17 @@
 
       /* calculate the average value for a single star */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-      m = catalog[i].average[j].measureOffset;
+      if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) { continue;  }
+      m = catalog[i].averageT[j].measureOffset;
 
       N = 0;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
+      for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
+	int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	if (ecode != seccode) { continue;}
 	Mcal = getMcal  (m, i);
-	if (isnan(Mcal)) continue;
+	if (isnan(Mcal)) { continue;}
 	Mmos = getMmos  (m, i);
-	if (isnan(Mmos)) continue;
+	if (isnan(Mmos)) { continue; }
 	Mgrid = getMgrid (m, i);
-	if (isnan(Mgrid)) continue;
+	if (isnan(Mgrid)) { continue;}
 	N++;
       }
@@ -554,4 +638,5 @@
   }
 
+  // fprintf (stderr, "N1: %d, N2: %d, N3: %d, N4: %d, N0: %d\n", N1, N2, N3, N4, N0);
   liststats (list, dlist, n, &stats);
   free (list);
@@ -560,5 +645,6 @@
 }
 
-StatType statsStarX (Catalog *catalog, int Ncatalog) {
+// stats for a single secfilt at a time
+StatType statsStarX (Catalog *catalog, int Ncatalog, int Nsec) {
 
   off_t j, Ntot;
@@ -567,4 +653,6 @@
   StatType stats;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   Ntot = 0;
   for (i = 0; i < Ncatalog; i++) {
@@ -580,7 +668,7 @@
 
       /* calculate the average value for a single star */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-
-      Xm = catalog[i].secfilt[PhotNsec*j+PhotSec].Xm;
+      if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+	
+      Xm = catalog[i].secfilt[Nsecfilt*j+Nsec].Xm;
       if (Xm == NAN_S_SHORT) continue;
       list[n] = pow (10.0, 0.01*Xm);
@@ -596,5 +684,5 @@
 }
 
-StatType statsStarS (Catalog *catalog, int Ncatalog) {
+StatType statsStarS (Catalog *catalog, int Ncatalog, int Nsec) {
 
   int i, n;
@@ -604,4 +692,6 @@
   StatType stats;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   Ntot = 0;
   for (i = 0; i < Ncatalog; i++) {
@@ -617,7 +707,7 @@
 
       /* calculate the average value for a single star */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-
-      dM = catalog[i].secfilt[PhotNsec*j+PhotSec].dM;
+      if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+
+      dM = catalog[i].secfilt[Nsecfilt*j+Nsec].dM;
       list[n] = dM;
       dlist[n] = 1;
@@ -644,20 +734,28 @@
   ALLOCATE (Mlist, double, NBIN);
 
-  for (i = 0; i < NBIN; i++) xlist[i] = 0.00025*i;
-  bzero (Mlist, NBIN*sizeof(double));
-  for (i = 0; i < Ncatalog; i++) {
-    for (j = 0; j < catalog[i].Naverage; j++) {
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-      dMrel = catalog[i].secfilt[PhotNsec*j+PhotSec].dM;
-      bin = dMrel / 0.00025;
-      bin = MAX (0, MIN (NBIN-1, bin));
-      Mlist[bin] += 1.0;
-    }
-  }
-
-  plot_defaults (&graphdata);
-  graphdata.style = 1;
-  plot_list (&graphdata, xlist, Mlist, NBIN, "dMrel hist", "%s.dMhist.png", OUTROOT);
-
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  int Ns;
+  for (Ns = 0; Ns < Nphotcodes; Ns++) {
+
+    int thisCode = photcodes[Ns][0].code;
+    int Nsec = GetPhotcodeNsec(thisCode);
+
+    for (i = 0; i < NBIN; i++) xlist[i] = 0.00025*i;
+    bzero (Mlist, NBIN*sizeof(double));
+    for (i = 0; i < Ncatalog; i++) {
+      for (j = 0; j < catalog[i].Naverage; j++) {
+	if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+	dMrel = catalog[i].secfilt[Nsecfilt*j+Nsec].dM;
+	bin = dMrel / 0.00025;
+	bin = MAX (0, MIN (NBIN-1, bin));
+	Mlist[bin] += 1.0;
+      }
+    }
+
+    plot_defaults (&graphdata);
+    graphdata.style = 1;
+    plot_list (&graphdata, xlist, Mlist, NBIN, "dMrel hist", "%s.dMhist.png", OUTROOT);
+  }
   free (xlist);
   free (Mlist);
@@ -671,4 +769,6 @@
   Graphdata graphdata;
 
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
   Ntotal = 0;
   for (i = 0; i < Ncatalog; i++) Ntotal += catalog[i].Naverage;
@@ -677,19 +777,27 @@
   ALLOCATE (ylist, double, Ntotal);
 
-  N = 0;
-  for (i = 0; i < Ncatalog; i++) {
-    for (j = 0; j < catalog[i].Naverage; j++) {
-      if (catalog[i].average[j].flags & STAR_BAD) continue;
-      xlist[N] = catalog[i].secfilt[PhotNsec*j+PhotSec].M;
-      value    = catalog[i].secfilt[PhotNsec*j+PhotSec].Xm;
-      if (value == NAN_S_SHORT) continue;
-      ylist[N] = 0.01*value;
-      N++;
-    }
-  }
-
-  plot_defaults (&graphdata);
-  graphdata.ymin = -3.0;
-  plot_list (&graphdata, xlist, ylist, N, "chisq", "%s.chisq.png", OUTROOT);
+  int Ns;
+  for (Ns = 0; Ns < Nphotcodes; Ns++) {
+
+    int thisCode = photcodes[Ns][0].code;
+    int Nsec = GetPhotcodeNsec(thisCode);
+
+    N = 0;
+    for (i = 0; i < Ncatalog; i++) {
+      for (j = 0; j < catalog[i].Naverage; j++) {
+	if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;
+	xlist[N] = catalog[i].secfilt[Nsecfilt*j+Nsec].M;
+	value    = catalog[i].secfilt[Nsecfilt*j+Nsec].Xm;
+	if (value == NAN_S_SHORT) continue;
+	ylist[N] = 0.01*value;
+	N++;
+      }
+    }
+
+    plot_defaults (&graphdata);
+    graphdata.ymin = -3.0;
+    plot_list (&graphdata, xlist, ylist, N, "chisq", "%s.chisq.png", OUTROOT);
+  }
+
   free (xlist);
   free (ylist);
@@ -716,6 +824,6 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-      xlist[N] = catalog[i].average[j].R;
-      ylist[N] = catalog[i].average[j].D;
+      xlist[N] = catalog[i].averageT[j].R;
+      ylist[N] = catalog[i].averageT[j].D;
       N++;
     }
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/args.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/args.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/args.c	(revision 31606)
@@ -128,4 +128,12 @@
   }
 
+  MaxDensityUse = FALSE;
+  if ((N = get_argument (argc, argv, "-max-density"))) {
+    remove_argument (N, &argc, argv);
+    MaxDensityValue = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    MaxDensityUse = TRUE;
+  }
+
   SHOW_PARAMS = FALSE;
   if ((N = get_argument (argc, argv, "-params"))) {
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/bcatalog.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/bcatalog.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/bcatalog.c	(revision 31606)
@@ -1,16 +1,49 @@
 # include "relphot.h"
+
+extern double drand48();
+
+int CopyAverageTiny (AverageTiny *averageT, Average *average) {
+
+  averageT[0].R     = average[0].R;
+  averageT[0].D     = average[0].D;
+  averageT[0].flags = average[0].flags;
+  averageT[0].Nmeasure      = average[0].Nmeasure;
+  averageT[0].measureOffset = average[0].measureOffset;
+
+  // make Nmeasure & measureOffset optional?
+
+  return (TRUE);
+}
+
+int CopyMeasureTiny (MeasureTiny *measureT, Measure *measure) {
+
+  measureT[0].dR       = measure[0].dR;
+  measureT[0].dD       = measure[0].dD;
+  measureT[0].M        = measure[0].M;
+  measureT[0].Mcal     = measure[0].Mcal;
+  measureT[0].dM       = measure[0].dM;
+  measureT[0].airmass  = measure[0].airmass;
+  measureT[0].Xccd     = measure[0].Xccd;
+  measureT[0].Yccd     = measure[0].Yccd;
+  measureT[0].t        = measure[0].t;
+  measureT[0].dt       = measure[0].dt;
+  measureT[0].averef   = measure[0].averef;
+  measureT[0].imageID  = measure[0].imageID;
+  measureT[0].dbFlags  = measure[0].dbFlags;
+  measureT[0].photcode = measure[0].photcode;
+
+  return (TRUE);
+}
 
 int bcatalog (Catalog *subcatalog, Catalog *catalog) {
   
   off_t i, j, offset;
-  int ecode;
+  int ecode, found, Ns;
   off_t NAVERAGE, NMEASURE, Naverage, Nmeasure, Nm;
   float mag;
   int Ncode, Ntime, Ndophot, Nmag, Nsigma, Nimag, Nfew, Ngalaxy, Npsfqf;
 
-  // XXX PhotNsec as a global is a bad idea; either get it from catalog
-  // or get it from:
-  // Nsecfilt = GetPhotcodeNsecfilt ();
-  // assert (catalog[0].Nsecfilt == Nsecfilt);
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+  assert (Nsecfilt == catalog[0].Nsecfilt);
 
   /* we are moving only the subset of measurements from catalog[0] to subcatalog[0] */
@@ -18,7 +51,7 @@
   NAVERAGE = 50;
   NMEASURE = 1000;
-  ALLOCATE (subcatalog[0].average, Average, NAVERAGE);
-  ALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*PhotNsec);
-  ALLOCATE (subcatalog[0].measure, Measure, NMEASURE);
+  ALLOCATE (subcatalog[0].measureT, MeasureTiny, NMEASURE);
+  ALLOCATE (subcatalog[0].averageT, AverageTiny, NAVERAGE);
+  ALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*Nsecfilt);
   Nmeasure = Naverage = 0;
 
@@ -30,15 +63,23 @@
 
     /* start with all stars good */
-    subcatalog[0].average[Naverage] = catalog[0].average[i];
-    subcatalog[0].average[Naverage].measureOffset = Nmeasure;
-    for (j = 0; j < PhotNsec; j++) {
-      subcatalog[0].secfilt[PhotNsec*Naverage+j] = catalog[0].secfilt[PhotNsec*i+j];
+    CopyAverageTiny (&subcatalog[0].averageT[Naverage], &catalog[0].average[i]);
+    subcatalog[0].averageT[Naverage].measureOffset = Nmeasure;
+
+    for (j = 0; j < Nsecfilt; j++) {
+      subcatalog[0].secfilt[Nsecfilt*Naverage+j] = catalog[0].secfilt[Nsecfilt*i+j];
     }
 
     if (RESET) {
-      subcatalog[0].secfilt[PhotNsec*Naverage+PhotSec].M  = NAN;
-      subcatalog[0].secfilt[PhotNsec*Naverage+PhotSec].dM = NAN;
-      subcatalog[0].average[Naverage].flags &= ~ID_STAR_FEW;
-      subcatalog[0].average[Naverage].flags &= ~ID_STAR_POOR;
+      int Ns;
+      for (Ns = 0; Ns < Nphotcodes; Ns++) {
+
+	int thisCode = photcodes[Ns][0].code;
+	int Nsec = GetPhotcodeNsec(thisCode);
+
+	subcatalog[0].secfilt[Nsecfilt*Naverage+Nsec].M  = NAN;
+	subcatalog[0].secfilt[Nsecfilt*Naverage+Nsec].dM = NAN;
+	subcatalog[0].secfilt[Nsecfilt*Naverage+Nsec].flags &= ~ID_STAR_FEW;
+	subcatalog[0].secfilt[Nsecfilt*Naverage+Nsec].flags &= ~ID_STAR_POOR;
+      }
     }
 
@@ -52,5 +93,12 @@
       /* select measurements by photcode */
       ecode = GetPhotcodeEquivCodebyCode (catalog[0].measure[offset].photcode);
-      if (ecode != photcode[0].code) { Ncode ++; continue; }
+      found = FALSE;
+      for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	if (ecode == photcodes[Ns][0].code) found = TRUE;
+      }
+      if (!found) {
+	Ncode ++; 
+	continue; 
+      }
 
       /* select measurements by time */
@@ -61,6 +109,4 @@
 
       /* select measurements by quality */
-      // XXX ignore this criterion for REF measurements?
-      // XXX chnage this to select by bitflags
       if (DophotSelect && ((catalog[0].measure[offset].photFlags >> 16) != DophotValue)) { Ndophot ++; continue; }
 
@@ -70,9 +116,9 @@
       // check for galaxies
       if (!isnan(catalog[0].measure[offset].Map)) {
-	  if (catalog[0].measure[offset].M - catalog[0].measure[offset].Map > 0.15) {
-	      nEXT ++;
-	  } else {
-	      nPSF ++;
-	  }
+	if (catalog[0].measure[offset].M - catalog[0].measure[offset].Map > 0.15) {
+	  nEXT ++;
+	} else {
+	  nPSF ++;
+	}
       }
 
@@ -91,13 +137,13 @@
       }
 
-      subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
-      subcatalog[0].measure[Nmeasure]        = catalog[0].measure[offset];
-      subcatalog[0].measure[Nmeasure].averef = Naverage;
+      CopyMeasureTiny (&subcatalog[0].measureT[Nmeasure], &catalog[0].measure[offset]);
+      subcatalog[0].measureT[Nmeasure].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
+      subcatalog[0].measureT[Nmeasure].averef = Naverage;
       if (RESET) { 
-	subcatalog[0].measure[Nmeasure].Mcal = 0;
-	subcatalog[0].measure[Nmeasure].dbFlags &= 0xff00;
-	subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_POOR_PHOTOM;
-	subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_AREA;
-	subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_NOCAL;
+	subcatalog[0].measureT[Nmeasure].Mcal = 0;
+	subcatalog[0].measureT[Nmeasure].dbFlags &= 0xff00;
+	subcatalog[0].measureT[Nmeasure].dbFlags &= ~ID_MEAS_POOR_PHOTOM;
+	subcatalog[0].measureT[Nmeasure].dbFlags &= ~ID_MEAS_AREA;
+	subcatalog[0].measureT[Nmeasure].dbFlags &= ~ID_MEAS_NOCAL;
       }
       Nmeasure ++;
@@ -105,5 +151,5 @@
       if (Nmeasure == NMEASURE) {
 	NMEASURE += 1000;
-	REALLOCATE (subcatalog[0].measure, Measure, NMEASURE);
+	REALLOCATE (subcatalog[0].measureT, MeasureTiny, NMEASURE);
       }
     }
@@ -122,20 +168,24 @@
       continue; 
     }
-    subcatalog[0].average[Naverage].Nmeasure = Nm;
+    subcatalog[0].averageT[Naverage].Nmeasure = Nm;
     Naverage ++;
     if (Naverage == NAVERAGE) {
       NAVERAGE += 50;
-      REALLOCATE (subcatalog[0].average, Average, NAVERAGE);
-      REALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*PhotNsec);
-    }
-  }
-  REALLOCATE (subcatalog[0].average, Average, MAX (Naverage, 1));
-  REALLOCATE (subcatalog[0].measure, Measure, MAX (Nmeasure, 1));
-  REALLOCATE (subcatalog[0].secfilt, SecFilt, PhotNsec*MAX (Naverage, 1));
+      REALLOCATE (subcatalog[0].averageT, AverageTiny, NAVERAGE);
+      REALLOCATE (subcatalog[0].secfilt,  SecFilt,     NAVERAGE*Nsecfilt);
+    }
+  }
+  REALLOCATE (subcatalog[0].averageT, AverageTiny, MAX (Naverage, 1));
+  REALLOCATE (subcatalog[0].measureT, MeasureTiny, MAX (Nmeasure, 1));
+  REALLOCATE (subcatalog[0].secfilt, SecFilt, Nsecfilt*MAX (Naverage, 1));
   subcatalog[0].Naverage = Naverage;
   subcatalog[0].Nmeasure = Nmeasure;
   subcatalog[0].Nsecfilt = catalog[0].Nsecfilt;
   subcatalog[0].Nsecf_mem = Naverage * catalog[0].Nsecfilt;
-  assert (PhotNsec == catalog[0].Nsecfilt);
+
+  // limit the total number of stars in the catalog
+  if (MaxDensityUse) {
+    LimitDensityCatalog (subcatalog, catalog);
+  }
 
   if (VERBOSE) {
@@ -147,2 +197,119 @@
   return (TRUE);
 }
+
+int LimitDensityCatalog (Catalog *subcatalog, Catalog *catalog) {
+
+  Catalog tmpcatalog;
+
+  double Rmin, Rmax, Dmin, Dmax;
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  gfits_scan (&catalog[0].header, "RA0",  "%lf", 1, &Rmin);
+  gfits_scan (&catalog[0].header, "DEC0", "%lf", 1, &Dmin);
+  gfits_scan (&catalog[0].header, "RA1",  "%lf", 1, &Rmax);
+  gfits_scan (&catalog[0].header, "DEC1", "%lf", 1, &Dmax);
+
+  if (VERBOSE2) fprintf (stderr, "extracting from catalog covering region %f,%f to %f,%f\n", Rmin, Dmin, Rmax, Dmax);
+
+  float AREA = fabs(Dmax - Dmin) * fabs(Rmax - Rmin) * cos (0.5*RAD_DEG*(Dmax + Dmin));
+  assert (AREA > 0);
+
+  off_t Nmax = MaxDensityValue * AREA;
+  if (subcatalog[0].Naverage <= Nmax) {
+    if (VERBOSE) {
+      fprintf (stderr, "subcatalog has less than the max density\n");
+    }
+    return (TRUE);
+  }
+
+  off_t Naverage = subcatalog[0].Naverage;
+
+  // select a random subset of Nmax stars from subcatalog using Fisher-Yates
+
+  // we are going to select Nmax entries by generating a random-sorted index list
+  off_t *index, tmp, i, j, ave;
+  ALLOCATE (index, off_t, Naverage);
+  for (i = 0; i < Naverage; i++) {
+    index[i] = i;
+  }
+  for (i = 0; i < Naverage; i++) {
+    j = (Naverage - i) * drand48() + i; // a number between i and Naverage
+    tmp = index[j];
+    index[j] = index[i];
+    index[i] = tmp;
+  }
+
+  // count the number of measurements this selection will yield
+  off_t NMEASURE = 0;
+  for (i = 0; i < Nmax; i++) {
+    ave = index[i];
+    NMEASURE += subcatalog[0].averageT[ave].Nmeasure;
+  }
+
+  // allocate the output data 
+  ALLOCATE (tmpcatalog.averageT, AverageTiny, Nmax);
+  ALLOCATE (tmpcatalog.measureT, MeasureTiny, NMEASURE);
+  ALLOCATE (tmpcatalog.secfilt,  SecFilt, Nmax * Nsecfilt);
+
+  off_t Nmeasure = 0;
+
+  // copy the Nmax selected entries from subcatalog to tmpcatalog (adjusting links)
+  for (i = 0; i < Nmax; i++) {
+    ave = index[i];
+    tmpcatalog.averageT[i] = subcatalog[0].averageT[ave];
+    tmpcatalog.averageT[i].measureOffset = Nmeasure;
+    for (j = 0; j < tmpcatalog.averageT[i].Nmeasure; j++) {
+      off_t offset = subcatalog[0].averageT[ave].measureOffset + j;
+      tmpcatalog.measureT[Nmeasure] = subcatalog[0].measureT[offset];
+      tmpcatalog.measureT[Nmeasure].averef = i;
+      Nmeasure ++;
+    }
+  }
+
+  if (VERBOSE) {
+    fprintf (stderr, "limited to "OFF_T_FMT" of "OFF_T_FMT" stars ("OFF_T_FMT" of "OFF_T_FMT" measures) for catalog %s\n", 
+	     Nmax, subcatalog[0].Naverage, Nmeasure, subcatalog[0].Nmeasure,  catalog[0].filename);
+  }
+
+  free (subcatalog[0].averageT);
+  free (subcatalog[0].measureT);
+  free (subcatalog[0].secfilt);
+
+  subcatalog[0].averageT = tmpcatalog.averageT;
+  subcatalog[0].measureT = tmpcatalog.measureT;
+  subcatalog[0].secfilt = tmpcatalog.secfilt;
+  subcatalog[0].Naverage = Nmax;
+  subcatalog[0].Nmeasure = Nmeasure;
+  subcatalog[0].Nsecfilt = catalog[0].Nsecfilt;
+  subcatalog[0].Nsecf_mem = Naverage * catalog[0].Nsecfilt;
+
+  return (TRUE);
+}
+
+// for the cases where we are not using a subset of the data, we still need to have a copy of these fields
+int populate_tiny_values (Catalog *catalog) {
+
+  off_t i;
+
+  ALLOCATE (catalog[0].measureT, MeasureTiny, catalog[0].Nmeasure);
+  ALLOCATE (catalog[0].averageT, AverageTiny, catalog[0].Naverage);
+
+  for (i = 0; i < catalog[0].Naverage; i++) {
+    CopyAverageTiny (&catalog[0].averageT[i], &catalog[0].average[i]);
+  }
+
+  for (i = 0; i < catalog[0].Nmeasure; i++) {
+    CopyMeasureTiny (&catalog[0].measureT[i], &catalog[0].measure[i]);
+  }
+
+  return (TRUE);
+}
+
+int free_tiny_values (Catalog *catalog) {
+
+  free (catalog[0].averageT);
+  free (catalog[0].measureT);
+  return (TRUE);
+}
+
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/global_stats.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/global_stats.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/global_stats.c	(revision 31606)
@@ -7,34 +7,44 @@
   initstats ("MEAN");
 
-  stN = statsStarN (catalog, Ncatalog);
-  stX = statsStarX (catalog, Ncatalog);
-  stS = statsStarS (catalog, Ncatalog);
+  fprintf (stderr, "\n");
+  fprintf (stderr, "STATS            median     mean    sigma      min      max   Nmeas\n");
 
+  int Ns;
+  for (Ns = 0; Ns < Nphotcodes; Ns++) {
+
+    int thisCode = photcodes[Ns][0].code;
+    int Nsec = GetPhotcodeNsec(thisCode);
+    int seccode = photcodes[Ns][0].code;
+
+    stN = statsStarN (catalog, Ncatalog, Nsec, seccode);
+    stX = statsStarX (catalog, Ncatalog, Nsec);
+    stS = statsStarS (catalog, Ncatalog, Nsec);
+  
+    fprintf (stderr, "   --- stats for %s ---\n", photcodes[Ns][0].name);
+    fprintf (stderr, "meas / star:    %7.0f  %7.1f  %7.1f  %7.0f  %7.0f  %6d\n",   stN.median, stN.mean, stN.sigma, stN.min, stN.max, stN.Nmeas);
+    fprintf (stderr, "dMrel star:     %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n", stS.median, stS.mean, stS.sigma, stS.min, stS.max, stS.Nmeas);
+    fprintf (stderr, "chisq star:     %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   stX.median, stX.mean, stX.sigma, stX.min, stX.max, stX.Nmeas);
+  }
+  
   imN = statsImageN (catalog);
   imX = statsImageX (catalog);
   imM = statsImageM (catalog);
   imD = statsImagedM (catalog);
-
+  
   msN = statsMosaicN (catalog);
   msM = statsMosaicM (catalog);
   msD = statsMosaicdM (catalog);
   msX = statsMosaicX (catalog);
-
-  fprintf (stderr, "STATS            median     mean    sigma      min      max   Nmeas\n");
+  
   fprintf (stderr, "meas / image:   %7.0f  %7.0f  %7.0f  %7.0f  %7.0f  %6d\n",   imN.median, imN.mean, imN.sigma, imN.min, imN.max, imN.Nmeas);
-  fprintf (stderr, "meas / mosaic:  %7.0f  %7.0f  %7.0f  %7.0f  %7.0f  %6d\n",   msN.median, msN.mean, msN.sigma, msN.min, msN.max, msN.Nmeas);
-  fprintf (stderr, "meas / star:    %7.0f  %7.1f  %7.1f  %7.0f  %7.0f  %6d\n",   stN.median, stN.mean, stN.sigma, stN.min, stN.max, stN.Nmeas);
-
-  fprintf (stderr, "chisq image:    %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   imX.median, imX.mean, imX.sigma, imX.min, imX.max, imX.Nmeas);
-  fprintf (stderr, "chisq mosaic:   %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   msX.median, msX.mean, msX.sigma, msX.min, msX.max, msX.Nmeas);
-  fprintf (stderr, "chisq star:     %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   stX.median, stX.mean, stX.sigma, stX.min, stX.max, stX.Nmeas);
-
   fprintf (stderr, "Mcal image:     %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n",   imM.median, imM.mean, imM.sigma, imM.min, imM.max, imM.Nmeas);
   fprintf (stderr, "dMcal image:    %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n",   imD.median, imD.mean, imD.sigma, imD.min, imD.max, imD.Nmeas);
+  fprintf (stderr, "chisq image:    %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   imX.median, imX.mean, imX.sigma, imX.min, imX.max, imX.Nmeas);
 
+  fprintf (stderr, "meas / mosaic:  %7.0f  %7.0f  %7.0f  %7.0f  %7.0f  %6d\n",   msN.median, msN.mean, msN.sigma, msN.min, msN.max, msN.Nmeas);
   fprintf (stderr, "Mcal mosaic:    %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n",   msM.median, msM.mean, msM.sigma, msM.min, msM.max, msM.Nmeas);
   fprintf (stderr, "dMcal mosaic:   %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n",   msD.median, msD.mean, msD.sigma, msD.min, msD.max, msD.Nmeas);
-
-  fprintf (stderr, "dMrel star:     %7.4f  %7.4f  %7.4f  %7.4f  %7.4f  %6d\n\n", stS.median, stS.mean, stS.sigma, stS.min, stS.max, stS.Nmeas);
+  fprintf (stderr, "chisq mosaic:   %7.1f  %7.1f  %7.1f  %7.1f  %7.1f  %6d\n",   msX.median, msX.mean, msX.sigma, msX.min, msX.max, msX.Nmeas);
+  
 
   initstats (STATMODE);
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/initialize.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/initialize.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/initialize.c	(revision 31606)
@@ -13,4 +13,6 @@
     N = UserPatchSelect ? 1 : 2;
 
+# if (0)
+    // XXX DEP
     if ((photcode = GetPhotcodebyName (argv[N])) == NULL) {
       fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", argv[N]);
@@ -21,8 +23,39 @@
       exit (1);
     }
+    // PhotSec is used to select the single average photcode being processed
     PhotSec = GetPhotcodeNsec (photcode[0].code);
+# endif
+
+    Nphotcodes = 0;
+    photcodes = NULL;
+    int NPHOTCODES = 10;
+    ALLOCATE (photcodes, PhotCode *, NPHOTCODES);
+
+    /* parse the comma-separated list of photcodesKeep */
+    char *myList = strcreate(argv[N]);
+    char *list = myList;
+    char *codename = NULL;
+    char *ptr = NULL;
+    while ((codename = strtok_r (list, ",", &ptr)) != NULL) {
+      list = NULL; // pass NULL on successive strtok_r calls
+      fprintf (stderr, "PHOTCODE LIST: %s\n", myList);
+      fprintf (stderr, "codename: %s\n", codename);
+      if ((photcodes[Nphotcodes] = GetPhotcodebyName (codename)) == NULL) {
+        fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", codename);
+        exit (1);
+      }
+      if (photcodes[Nphotcodes][0].type != PHOT_SEC) {
+	  fprintf (stderr, "photcode %s is not an filter type (SEC)\n", codename);
+	  exit (1);
+      }
+      Nphotcodes ++;
+      CHECK_REALLOCATE (photcodes, PhotCode *, NPHOTCODES, Nphotcodes, 10);
+    }
   }
-
-  PhotNsec = GetPhotcodeNsecfilt ();
+  // XXX DEP PhotNsec = GetPhotcodeNsecfilt ();
+  if (USE_GRID && (Nphotcodes > 1)) {
+    fprintf (stderr, "grid correction analysis currently can only operate on a single photcode\n");
+    exit (1);
+  }
 
   initstats (STATMODE);
@@ -55,4 +88,9 @@
     exit (0);
   }
+
+  // init the random seed
+  long A, B;
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
 }
-
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/load_images.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/load_images.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/load_images.c	(revision 31606)
@@ -44,5 +44,5 @@
   // select the images which overlap the selected sky regions
   subset = select_images (skylist, image, Nimage, &LineNumber, &Nsubset);
-  MARKTIME("selected images: %f sec\n", dtime);
+  MARKTIME("selected %d overlapping images: %f sec\n", (int) Nsubset, dtime);
 
   // generate db->vtable from db->ftable based on the selection
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/plot_scatter.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/plot_scatter.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/plot_scatter.c	(revision 31606)
@@ -18,41 +18,54 @@
   ALLOCATE (ilist, double, Ntot);
 
-  N = 0;
-  for (i = 0; i < Ncatalog; i++) {
-    for (j = 0; j < catalog[i].Naverage; j++) {
+  int Nsecfilt = GetPhotcodeNsecfilt ();
 
-      /* calculate the average value for a single star */
-      if (catalog[i].average[j].flags & STAR_BAD) continue;  
-      m = catalog[i].average[j].measureOffset;
+  int Ns;
+  for (Ns = 0; Ns < Nphotcodes; Ns++) {
 
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
-	if (catalog[i].measure[m].dbFlags & MEAS_BAD) continue;
-	Mcal = getMcal  (m, i);
-	if (isnan(Mcal)) continue;
-	Mmos = getMmos  (m, i);
-	if (isnan(Mmos)) continue;
-	Mgrid = getMgrid (m, i);
-	if (isnan(Mgrid)) continue;
+    int thisCode = photcodes[Ns][0].code;
+    int Nsec = GetPhotcodeNsec(thisCode);
 
-	Mrel = catalog[i].secfilt[PhotNsec*j+PhotSec].M;
-	xlist[N] = Mrel;
-	ylist[N] = PhotSys  (&catalog[i].measure[m], &catalog[i].average[j], &catalog[i].secfilt[j*PhotNsec]) - Mcal - Mmos - Mgrid - Mrel;
-	ilist[N] = PhotInst (&catalog[i].measure[m]);
-	N++;
-      }
+    N = 0;
+    for (i = 0; i < Ncatalog; i++) {
+	for (j = 0; j < catalog[i].Naverage; j++) {
+
+	    /* calculate the average value for a single star */
+	    if (catalog[i].secfilt[Nsecfilt*j+Nsec].flags & STAR_BAD) continue;  
+	    m = catalog[i].average[j].measureOffset;
+
+	    for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
+		// skip measurements that do not match the current photcode
+		int ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+		if (ecode != thisCode) { continue; }
+
+		if (catalog[i].measureT[m].dbFlags & MEAS_BAD) continue;
+		Mcal = getMcal  (m, i);
+		if (isnan(Mcal)) continue;
+		Mmos = getMmos  (m, i);
+		if (isnan(Mmos)) continue;
+		Mgrid = getMgrid (m, i);
+		if (isnan(Mgrid)) continue;
+
+		Mrel = catalog[i].secfilt[Nsecfilt*j+Nsec].M;
+		xlist[N] = Mrel;
+		ylist[N] = PhotSysTiny (&catalog[i].measureT[m], &catalog[i].averageT[j], &catalog[i].secfilt[j*Nsecfilt]) - Mcal - Mmos - Mgrid - Mrel;
+		ilist[N] = PhotInstTiny (&catalog[i].measureT[m]);
+		N++;
+	    }
+	}
     }
+
+    plot_defaults (&graphdata);
+    graphdata.xmin = PlotMmin;
+    graphdata.xmax = PlotMmax;
+    graphdata.ymin = PlotdMmin;
+    graphdata.ymax = PlotdMmax;
+    plot_list (&graphdata, xlist, ylist, N, "mag vs dmag", "%s.Mag.png", OUTROOT);
+
+    plot_defaults (&graphdata);
+    graphdata.ymin = PlotdMmin;
+    graphdata.ymax = PlotdMmax;
+    plot_list (&graphdata, ilist, ylist, N, "imag vs dmag", "%s.iMag.png", OUTROOT);
   }
-
-  plot_defaults (&graphdata);
-  graphdata.xmin = PlotMmin;
-  graphdata.xmax = PlotMmax;
-  graphdata.ymin = PlotdMmin;
-  graphdata.ymax = PlotdMmax;
-  plot_list (&graphdata, xlist, ylist, N, "mag vs dmag", "%s.Mag.png", OUTROOT);
-
-  plot_defaults (&graphdata);
-  graphdata.ymin = PlotdMmin;
-  graphdata.ymax = PlotdMmax;
-  plot_list (&graphdata, ilist, ylist, N, "imag vs dmag", "%s.iMag.png", OUTROOT);
   free (xlist);
   free (ylist);
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/reload_catalogs.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/reload_catalogs.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/reload_catalogs.c	(revision 31606)
@@ -1,3 +1,9 @@
 # include "relphot.h"
+
+# define TIMESTAMP(TIME) \
+    gettimeofday (&stop, (void *) NULL);	\
+    dtime = DTIME (stop, start);		\
+    TIME += dtime;				\
+    gettimeofday (&start, (void *) NULL);
 
 void reload_catalogs (SkyList *skylist) {
@@ -8,8 +14,19 @@
   Catalog catalog;
 
+  struct timeval start, stop;
+  double dtime = 0.0;
+  double time1 = 0.0;
+  double time2 = 0.0;
+  double time3 = 0.0;
+  double time4 = 0.0;
+  double time5 = 0.0;
+  double time6 = 0.0;
+  double time7 = 0.0;
+
   if (VERBOSE) fprintf (stderr, "re-loading catalog data\n");
 
   /* load data from each region file */
   for (i = 0; i < skylist[0].Nregions; i++) {
+    gettimeofday (&start, (void *) NULL);
     catalog.filename = skylist[0].filename[i];
 
@@ -20,4 +37,5 @@
       continue;
     }
+    TIMESTAMP(time1);
 
     catalog.catformat = dvo_catalog_catformat (CATFORMAT);    // set the default catformat from config data
@@ -36,20 +54,39 @@
 	continue;
     }
+    TIMESTAMP(time2);
+
+    populate_tiny_values(&catalog);
 
     initImageBins  (&catalog, 1);
     initMosaicBins (&catalog, 1);
-    initGridBins   (&catalog, 1);
+    initGridBins   (&catalog, 1); 
+    TIMESTAMP(time3);
 
-    findImages (&catalog, 1);
-    findMosaics (&catalog, 1);
+    findImages (&catalog, 1);  // FX
+    findMosaics (&catalog, 1); // 
+    TIMESTAMP(time4);
 
     setMrelFinal (&catalog);
+    TIMESTAMP(time5);
+
     dvo_catalog_save (&catalog, VERBOSE); 
     dvo_catalog_unlock (&catalog);
+
+    free_tiny_values(&catalog);
     dvo_catalog_free (&catalog);
+    TIMESTAMP(time6);
 
     freeImageBins (1);
     freeMosaicBins (1);
     freeGridBins (1);
+    TIMESTAMP(time7);
   }
+
+  fprintf (stderr, "time1 %f : find catalog\n", time1);
+  fprintf (stderr, "time2 %f : load catalog\n", time2);
+  fprintf (stderr, "time3 %f : init imbins\n",  time3);
+  fprintf (stderr, "time4 %f : find images\n",  time4);
+  fprintf (stderr, "time5 %f : set Mrel\n",     time5);
+  fprintf (stderr, "time6 %f : save catalog\n", time6);
+  fprintf (stderr, "time7 %f : free catalog\n", time7);
 }
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot.c	(revision 31606)
@@ -47,5 +47,5 @@
     if (!dvo_image_load (&db, VERBOSE, FALSE)) Shutdown ("can't read image catalog %s", db.filename);
   }
-  MARKTIME("load image data: %f sec\n", dtime);
+  MARKTIME("-- load image data: %f sec\n", dtime);
 
   /* load regions and images based on specified sky patch */
@@ -54,5 +54,5 @@
   // XXX this is fairly lame: argv[1] is photcode if UserPatchSelect is true
   skylist = load_images (&db, argv[1], &UserPatch, UserPatchSelect);
-  MARKTIME("load images: %f sec\n", dtime);
+  MARKTIME("-- load images: %f sec\n", dtime);
 
   /* unlock, if we can (else, unlocked below) */
@@ -61,5 +61,5 @@
   /* load catalog data from region files */
   catalog = load_catalogs (skylist, &Ncatalog);
-  MARKTIME("load catalog data: %f sec\n", dtime);
+  MARKTIME("-- load catalog data: %f sec\n", dtime);
   
   /* add in a loop over the catalogs calling dvo_catalog_chipcoords */
@@ -67,5 +67,5 @@
   /* match measurements with images, mosaics */
   initImageBins  (catalog, Ncatalog);
-  MARKTIME("make image bins: %f sec\n", dtime);
+  MARKTIME("-- make image bins: %f sec\n", dtime);
 
   initMosaicBins (catalog, Ncatalog);
@@ -74,12 +74,14 @@
 
   findImages (catalog, Ncatalog);
-  MARKTIME("set up image indexes: %f sec\n", dtime);
+  MARKTIME("-- set up image indexes: %f sec\n", dtime);
 
   findMosaics (catalog, Ncatalog);  /* also sets Grid values */
-  MARKTIME("set up mosaic indexes: %f sec\n", dtime);
+  MARKTIME("-- set up mosaic indexes: %f sec\n", dtime);
 
   SAVEPLOT = FALSE;
 
   setExclusions (catalog, Ncatalog);
+
+  global_stats (catalog, Ncatalog);
 
   if (PLOTSTUFF) {
@@ -91,22 +93,4 @@
   if (USE_GRID) {
       int star_toofew;
-
-# if (USE_DIRECT)
-      // until we finish the grid analysis, do not reject stars out-of-hand based on ID_STAR_FEW
-      // XXX this is kind of poor: need to have a better distinctions about STAR_BAD in setMrel vs getMrel
-      star_toofew = STAR_TOOFEW;
-      STAR_TOOFEW = 0;
-      STAR_BAD  = ID_STAR_POOR;
-
-      showGridCount ();
-      setMgridDirect (catalog, Ncatalog);
-
-      STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
-      STAR_TOOFEW = star_toofew;
-
-      dump_grid ();
-      exit (0);
-
-# else
 
       // until we finish the grid analysis, do not reject stars out-of-hand based on ID_STAR_FEW
@@ -122,5 +106,4 @@
       STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
       STAR_TOOFEW = star_toofew;
-# endif
   }
 
@@ -140,19 +123,28 @@
       plot_chisq (catalog, Ncatalog);
     }
-    if ((i == 1) || (i == 5) || (i ==  9) || (i == 13)) clean_measures (catalog, Ncatalog, FALSE); 
-    if ((i == 2) || (i == 6) || (i == 10) || (i == 14)) clean_stars (catalog, Ncatalog);
-    if ((i == 4) || (i == 8) || (i == 12) || (i == 16)) clean_mosaics ();
-    if ((i == 4) || (i == 8) || (i == 12) || (i == 16)) clean_images ();
+    if (i % 6 == 1) rationalize_mosaics (catalog, Ncatalog);
+    // if (i % 6 == 1) rationalize_images ();
+    if (i % 6 == 2) clean_measures (catalog, Ncatalog, FALSE); 
+    if (i % 6 == 3) clean_stars (catalog, Ncatalog);
+    if (i % 6 == 5) clean_mosaics ();
+    if (i % 6 == 5) clean_images ();
+
+    // if ((i == 1) || (i == 5) || (i ==  9) || (i == 13)) clean_measures (catalog, Ncatalog, FALSE); 
+    // if ((i == 2) || (i == 6) || (i == 10) || (i == 14)) clean_stars (catalog, Ncatalog);
+    // if ((i == 4) || (i == 8) || (i == 12) || (i == 16)) clean_mosaics ();
+    // if ((i == 4) || (i == 8) || (i == 12) || (i == 16)) clean_images ();
     global_stats (catalog, Ncatalog);
+    MARKTIME("-- finished loop %d: %f sec\n", i, dtime);
   }
 
-  SAVEPLOT = TRUE;
-  plot_scatter (catalog, Ncatalog); 
-  plot_grid (catalog); 
-  plot_mosaics ();
-  plot_images ();
-  plot_stars (catalog, Ncatalog);
-  plot_chisq (catalog, Ncatalog);
-
+  if (PLOTSTUFF) {
+    plot_scatter (catalog, Ncatalog); 
+    plot_grid (catalog); 
+    plot_mosaics ();
+    plot_images ();
+    plot_stars (catalog, Ncatalog);
+    plot_chisq (catalog, Ncatalog);
+  }
+  
   if (USE_GRID) dump_grid ();
   if (!UPDATE) exit (0);
@@ -161,7 +153,11 @@
   setMcal  (catalog, TRUE);
   setMmos  (catalog, TRUE);
+  MARKTIME("-- finalize Mcal values: %f sec\n", dtime);
 
   /* at this point, we have correct cal coeffs in the image/mosaic structures */
-  for (i = 0; i < Ncatalog; i++) dvo_catalog_free (&catalog[i]);
+  for (i = 0; i < Ncatalog; i++) {
+    free_tiny_values (&catalog[i]);
+    dvo_catalog_free (&catalog[i]);
+  }
   freeImageBins (Ncatalog);
   freeMosaicBins (Ncatalog);
@@ -170,6 +166,7 @@
   /* load catalog data from region files, update Mrel include all data */
   reload_catalogs (skylist);
+  MARKTIME("-- updated all catalogs: %f sec\n", dtime);
+
   setMcalFinal ();
-
   reload_images (&db);
   
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot_objects.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot_objects.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/relphot_objects.c	(revision 31606)
@@ -3,5 +3,5 @@
 int relphot_objects () {
 
-  off_t i, j, k, m;
+  off_t i, j, k;
   int Nsecfilt;
 
@@ -38,5 +38,5 @@
     }
 
-    // XXX consider what gets reset (only PHOTOM flags)
+    // reset 
     if (RESET) {
       Nsecfilt = catalog.Nsecfilt;
@@ -51,9 +51,5 @@
 	  catalog.secfilt[j*Nsecfilt + k].Ncode = 0;
 	  catalog.secfilt[j*Nsecfilt + k].Nused = 0;
-	}
-	m = catalog.average[j].measureOffset;
-	for (k = 0; k < catalog.average[j].Nmeasure; k++) {
-	  catalog.measure[m+k].dbFlags = 0;
-	  catalog.measure[m+k].Mcal = 0;
+	  // XXX reset the photometry flags for secfilt entries?
 	}
       }
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/select_images.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/select_images.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/select_images.c	(revision 31606)
@@ -64,4 +64,6 @@
   DmaxSkyRegion = -90.0;
 
+  // FILE *ftest = fopen ("relphot.dump.dat", "w");
+
   /* compare with each region file */
   for (i = 0; i < skylist[0].Nregions; i++) { 
@@ -117,5 +119,10 @@
     /* exclude images by photcode */
     ecode = GetPhotcodeEquivCodebyCode (timage[i].photcode);
-    if (ecode != photcode[0].code) continue;
+    found = FALSE;
+    int Ns;
+    for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	if (ecode == photcodes[Ns][0].code) found = TRUE;
+    }
+    if (!found) continue;
 
     /* exclude images by time */
@@ -130,4 +137,7 @@
       continue;
     }
+
+    // XXX temporary test : record center coords for each accepted and rejected chip/mosaic
+    // double RAo, DECo;
 
     /* define image corners - note the DIS images (mosaic phu) are special */
@@ -138,4 +148,5 @@
       Xi[3] = -0.5*timage[i].NX; Yi[3] = +0.5*timage[i].NY;
       Xi[4] = -0.5*timage[i].NX; Yi[4] = -0.5*timage[i].NY;
+      // XY_to_RD(&RAo, &DECo, 0.0, 0.0, &timage[i].coords);
     } else {
       Xi[0] = 0;            Yi[0] = 0;
@@ -144,10 +155,11 @@
       Xi[3] = 0;            Yi[3] = timage[i].NY;
       Xi[4] = 0;            Yi[4] = 0;
+      // XY_to_RD(&RAo, &DECo, 0.5*timage[i].NX, 0.5*timage[i].NY, &timage[i].coords);
     }
     found = FALSE;
 
     /* transform corners to ra,dec -- costs ~3sec for 3M images (pikake) */
-    double RminImage = 360.0;
-    double RmaxImage =   0.0;
+    double RminImage = RmidSkyRegion + 180.0;
+    double RmaxImage = RmidSkyRegion - 180.0;
     double DminImage = +90.0;
     double DmaxImage = -90.0;
@@ -218,4 +230,7 @@
 
   found_it:
+    // XXX We claim this is a good image: write to a test file
+    // fprintf (ftest, "%s : %lf %lf  : %f %f %d %x\n", timage[i].name, RAo, DECo, timage[i].Mcal, timage[i].dMcal, timage[i].nstar, timage[i].flags);
+
     image[nimage] = timage[i]; 
     /* always allow 'few' images to succeed, if possible */
@@ -239,4 +254,6 @@
   }
   MARKTIME("finish image selection: %f sec\n", dtime);
+
+  // fclose (ftest);
 
   if (VERBOSE) fprintf (stderr, "found "OFF_T_FMT" images\n", nimage);
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/setExclusions.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/setExclusions.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/setExclusions.c	(revision 31606)
@@ -1,8 +1,13 @@
 # include "relphot.h"
+
+// this function sets the NOCAL and AREA dbFlags bits for the MeasureTiny elements these
+// are used elsewhere (StarOps.c, ImageOps.c, MosaicOps.c, GridOps.c, etc) to skip bad
+// measurements.  The only exception is 'setMave' which is called by 'relphot_objects',
+// and uses the bits read from disk as the test
 
 int setExclusions (Catalog *catalog, int Ncatalog) {
 
   off_t i, j, k, m, Narea, Nnocal, Ngood;
-  int ecode;
+  int ecode, found, Ns;
   Coords *coords;
   double r, d, x, y;
@@ -11,21 +16,25 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
-      m = catalog[i].average[j].measureOffset;
-      for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
+      m = catalog[i].averageT[j].measureOffset;
+      for (k = 0; k < catalog[i].averageT[j].Nmeasure; k++, m++) {
 
 	/* select measurements by photcode */
-	ecode = GetPhotcodeEquivCodebyCode (catalog[i].measure[m].photcode);
-	if (ecode != photcode[0].code) goto mark_nocal;
+	ecode = GetPhotcodeEquivCodebyCode (catalog[i].measureT[m].photcode);
+	found = FALSE;
+	for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	    if (ecode == photcodes[Ns][0].code) found = TRUE;
+	}
+	if (!found) goto mark_nocal;
 	
 	/* select measurements by time */
 	if (TimeSelect) {
-	  if (catalog[i].measure[m].t < TSTART) goto mark_nocal;
-	  if (catalog[i].measure[m].t > TSTOP) goto mark_nocal;
+	  if (catalog[i].measureT[m].t < TSTART) goto mark_nocal;
+	  if (catalog[i].measureT[m].t > TSTOP) goto mark_nocal;
 	}
 
 	/* select measurements by mag limit */
 	if (AreaSelect) {
-	  r = catalog[i].average[j].R + catalog[i].measure[m].dR / 3600.0;
-	  d = catalog[i].average[j].D + catalog[i].measure[m].dD / 3600.0;
+	  r = catalog[i].averageT[j].R + catalog[i].measureT[m].dR / 3600.0;
+	  d = catalog[i].averageT[j].D + catalog[i].measureT[m].dD / 3600.0;
 	  if ((coords = getCoords (m, i)) == NULL) goto markbad;
 	  RD_to_XY (&x, &y, r, d, coords);
@@ -39,10 +48,10 @@
 
       markbad:
-	catalog[i].measure[m].dbFlags |= ID_MEAS_AREA;
+	catalog[i].measureT[m].dbFlags |= ID_MEAS_AREA;
 	Narea ++;
 	continue;
 	
       mark_nocal:
-	catalog[i].measure[m].dbFlags |= ID_MEAS_NOCAL;
+	catalog[i].measureT[m].dbFlags |= ID_MEAS_NOCAL;
 	Nnocal ++;
 	continue;
Index: /branches/czw_branch/20110406/Ohana/src/relphot/src/setMrelFinal.c
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/relphot/src/setMrelFinal.c	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/relphot/src/setMrelFinal.c	(revision 31606)
@@ -1,3 +1,7 @@
 # include "relphot.h"
+
+// we've just reloaded the data from disk; we now need to apply the Image/Mosaic/Grid
+// calibrations determined by the rest of the program.  We also need to set the final
+// output dbFlags values
 
 void setMrelFinal (Catalog *catalog) {
@@ -9,32 +13,42 @@
   if (RESET) {
 
-    for (i = 0; i < catalog[0].Naverage; i++) {
-      catalog[0].secfilt[PhotNsec*i+PhotSec].M  = NAN;
-      catalog[0].secfilt[PhotNsec*i+PhotSec].dM = NAN;
-      catalog[0].secfilt[PhotNsec*i+PhotSec].Xm = NAN_S_SHORT;
+    int Nsecfilt = GetPhotcodeNsecfilt ();
 
-      m = catalog[0].average[i].measureOffset;
-      for (j = 0; j < catalog[0].average[i].Nmeasure; j++, m++) {
+    int Ns;
+    for (Ns = 0; Ns < Nphotcodes; Ns++) {
 	
-	/* select measurements by photcode */
-	ecode = GetPhotcodeEquivCodebyCode (catalog[0].measure[m].photcode);
-	if (ecode != photcode[0].code) continue;
+      int thisCode = photcodes[Ns][0].code;
+      int Nsec = GetPhotcodeNsec(thisCode);
+
+      for (i = 0; i < catalog[0].Naverage; i++) {
+	catalog[0].secfilt[Nsecfilt*i+Nsec].M  = NAN;
+	catalog[0].secfilt[Nsecfilt*i+Nsec].dM = NAN;
+	catalog[0].secfilt[Nsecfilt*i+Nsec].Xm = NAN_S_SHORT;
+
+	m = catalog[0].average[i].measureOffset;
+	for (j = 0; j < catalog[0].average[i].Nmeasure; j++, m++) {
 	
-	/* select measurements by time */
-	if (TimeSelect) {
-	  if (catalog[0].measure[m].t < TSTART) continue;
-	  if (catalog[0].measure[m].t > TSTOP) continue;
+	  // skip measurements that do not match the current photcode
+	  ecode = GetPhotcodeEquivCodebyCode (catalog[0].measure[m].photcode);
+	  if (ecode != thisCode) { continue; }
+
+	  /* select measurements by time */
+	  if (TimeSelect) {
+	    if (catalog[0].measure[m].t < TSTART) continue;
+	    if (catalog[0].measure[m].t > TSTOP) continue;
+	  }
+	
+	  catalog[0].measure[m].Mcal = 0;
+	  catalog[0].measure[m].dbFlags &= 0xff00;
+	  catalog[0].measure[m].dbFlags &= ~ID_MEAS_POOR_PHOTOM;
+	  catalog[0].measure[m].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
+	  catalog[0].measure[m].dbFlags &= ~ID_MEAS_AREA;
+	  catalog[0].measure[m].dbFlags &= ~ID_MEAS_NOCAL;
 	}
-	
-	catalog[0].measure[m].Mcal = 0;
-	catalog[0].measure[m].dbFlags &= 0xff00;
-	catalog[0].measure[m].dbFlags &= ~ID_MEAS_POOR_PHOTOM;
-	catalog[0].measure[m].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
-	catalog[0].measure[m].dbFlags &= ~ID_MEAS_AREA;
-	catalog[0].measure[m].dbFlags &= ~ID_MEAS_NOCAL;
       }
     }
   }
 
+  // this sets flags in the measureT element, not the measure element
   setExclusions (catalog, 1);  /* mark by area */
 
@@ -53,8 +67,15 @@
   setMcalOutput (catalog, 1);
 
-  /* clear ID_STAR_POOR, ID_STAR_FEW, ID_MEAS_NOCAL values before writing ??? */
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  /* clear ID_STAR_POOR, ID_STAR_FEW values before writing ??? */
+  /* ID_MEAS_NOCAL is an internal bit, so it should be cleared */
   for (i = 0; i < catalog[0].Naverage; i++) {
     catalog[0].average[i].flags &= ~ID_STAR_FEW;
     catalog[0].average[i].flags &= ~ID_STAR_POOR;
+    for (j = 0; j < Nsecfilt; j++) {
+	catalog[0].secfilt[i*Nsecfilt+j].flags &= ~ID_STAR_FEW; 
+	catalog[0].secfilt[i*Nsecfilt+j].flags &= ~ID_STAR_POOR; 
+    }
     m = catalog[0].average[i].measureOffset;
     for (j = 0; j < catalog[0].average[i].Nmeasure; j++, m++) {
@@ -68,5 +89,5 @@
 
   off_t i, k, m;
-  int ecode;
+  int ecode, found, Ns;
   off_t Ntot, Ntry, Nkeep, Nskip;
   float mag;
@@ -90,10 +111,14 @@
 
       /* clear SKIP for all measures at first */
-      catalog[0].measure[m].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
+      catalog[0].measureT[m].dbFlags &= ~ID_MEAS_SKIP_PHOTOM;
 
       /** never use these measurements (wrong photcode, bad time range) */
       /* skipped via NOCAL, don't mark as skipped */
       ecode = GetPhotcodeEquivCodebyCode (catalog[0].measure[m].photcode);
-      if (ecode != photcode[0].code) continue;
+      found = FALSE;
+      for (Ns = 0; !found && (Ns < Nphotcodes); Ns++) {
+	if (ecode == photcodes[Ns][0].code) found = TRUE;
+      }
+      if (!found) continue;
 
       /* skip measurements by time range */
@@ -134,5 +159,6 @@
 
     skip:
-      catalog[0].measure[m].dbFlags |= ID_MEAS_SKIP_PHOTOM;
+      catalog[0].measure [m].dbFlags |= ID_MEAS_SKIP_PHOTOM;
+      catalog[0].measureT[m].dbFlags |= ID_MEAS_SKIP_PHOTOM;
       Nskip ++;
     }
Index: /branches/czw_branch/20110406/Ohana/src/skycalc/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/skycalc/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/skycalc/Makefile	(revision 31606)
@@ -75,6 +75,6 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(INSTALL); do make $$i.install || exit; done
+	for i in $(INSTALL); do $(MAKE) $$i.install || exit; done
Index: /branches/czw_branch/20110406/Ohana/src/tools/Makefile
===================================================================
--- /branches/czw_branch/20110406/Ohana/src/tools/Makefile	(revision 31605)
+++ /branches/czw_branch/20110406/Ohana/src/tools/Makefile	(revision 31606)
@@ -57,8 +57,8 @@
 
 %.install:
-	make $(DESTBIN)/$*
+	$(MAKE) $(DESTBIN)/$*
 
 install:
-	for i in $(PROGRAMS); do make $$i.install || exit; done
+	for i in $(PROGRAMS); do $(MAKE) $$i.install || exit; done
 
 
Index: /branches/czw_branch/20110406/dbconfig/changes.txt
===================================================================
--- /branches/czw_branch/20110406/dbconfig/changes.txt	(revision 31605)
+++ /branches/czw_branch/20110406/dbconfig/changes.txt	(revision 31606)
@@ -2132,2 +2132,5 @@
 UPDATE dbversion set schema_version = '1.1.70', updated= CURRENT_TIMESTAMP();
 
+-- heather discovered that we need keys for addRun:
+
+alter table addRun add key(stage), add key (stage_id);
Index: /branches/czw_branch/20110406/ippScripts/scripts/camera_exp.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/camera_exp.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/camera_exp.pl	(revision 31606)
@@ -153,4 +153,28 @@
     }
     chomp $cmdflags;
+
+    { # Determine if FWHM is too large to bother continuing.
+	my $command = "$ppConfigDump -camera $camera -dump-camera -";
+	my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	    run(command => $command, verbose => $verbose);
+	unless ($success) {
+	    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	    &my_die("Unable to perform ppConfigDump: $error_code", $cam_id, $PS_EXIT_CONFIG_ERROR);
+	}
+	my $cameraConfig = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", $cam_id, $PS_EXIT_CONFIG_ERROR);
+
+	my $maxFWHM = metadataLookupStr($cameraConfig, 'MAX_ALLOWED_FWHM');
+	if ($maxFWHM) {
+	    my $expFWHM;
+	    ($expFWHM) = $cmdflags =~ /-fwhm_major (\d+)/;	
+	    
+	    if ($expFWHM > $maxFWHM) {
+		print "Setting quality to 4007 due to large FWHM: exposure: $expFWHM  maximum: $maxFWHM\n";
+		$cmdflags .= " -quality 4007 "; # This corresponds to PSASTRO_ERR_DATA
+		$no_op = 1;
+	    }
+	}
+    }
 }
 
Index: /branches/czw_branch/20110406/ippScripts/scripts/dist_advancerun.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/dist_advancerun.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/dist_advancerun.pl	(revision 31606)
@@ -114,5 +114,5 @@
     $tool_cmd = "$staticskytool -sky_id";
     $list_mode = "-result";
-    $component_key = "";
+    $component_key = "skycell_id";
 } elsif ($stage eq "diff") {
     $tool_cmd = "$difftool -diff_id";
Index: /branches/czw_branch/20110406/ippScripts/scripts/dist_bundle.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/dist_bundle.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/dist_bundle.pl	(revision 31606)
@@ -62,4 +62,5 @@
 my $streaksrelease   = can_run('streaksrelease') or (warn "Can't find streaksrelease" and $missing_tools = 1);
 my $bgtool   = can_run('bgtool') or (warn "Can't find bgtool" and $missing_tools = 1);
+my $staticskytool   = can_run('staticskytool') or (warn "Can't find staticskytool" and $missing_tools = 1);
 my $file_cmd   = can_run('file') or (warn "can't find program file" and $missing_tools = 1);
 my $zcat   = can_run('zcat') or (warn "can't find program zcat" and $missing_tools = 1);
@@ -106,25 +107,30 @@
     defined $stage_id and
     defined $component and
-    defined $exp_type and
     defined $path_base and
     defined $outroot;
 
+if ($stage eq 'raw' and !$clean and !$no_magic) {
+    
+    # for raw stage need to have exposure type defined and if the type is OBJECT we need
+    # a chip_path_base so we can find the chip mask file
+    if (!defined $exp_type or ($exp_type eq 'OBJECT' and !defined $chip_path_base)) {
+        pod2usage( -msg => "Required options: --chip_path_base --exp_type for raw stage", -exitval => 3);
+    }
+}
+
 $ipprc->redirect_output($logfile) if $logfile;
 
-if ($stage eq 'raw' and !$clean and !$no_magic) {
-    # need to be able to find chip mask file
-    if ($exp_type eq 'OBJECT' and !defined $chip_path_base) {
-        pod2usage( -msg => "Required options: --chip_path_base for raw stage", -exitval => 3);
-    }
-}
-
 $ipprc->define_camera($camera);
 
 $ipprc->outroot_prepare($outroot);
 
+my $num_sky_inputs;
+if ($stage eq 'sky') {
+    $num_sky_inputs = get_num_sky_inputs($stage_id);
+}
 # Get the list of data products for this component
 # note: We my_die in get_file_list if something goes wrong.
 
-my $file_list = get_file_list($stage, $component, $path_base, $clean);
+my $file_list = get_file_list($stage, $component, $path_base, $clean, $num_sky_inputs);
 
 if (($stage ne 'raw') and ($stage ne 'fake') and !$poor_quality) {
@@ -184,4 +190,8 @@
         # it must exist)
         next if $poor_quality;
+
+        # skip file stats file. Due to a bug the update process destroys them sometimes
+        # XXX: perhaps only do this for stages where we know that this happens
+        next if $file_rule =~ /STATS/;
 
         &my_die("failed to resolve  $file_name", $component, $PS_EXIT_DATA_ERROR);
@@ -480,4 +490,5 @@
     my $path_base = shift;
     my $clean = shift;
+    my $num_sky_inputs = shift;
 
     my @file_list;
@@ -531,5 +542,9 @@
         $config_file_rule = "PPSTACK.CONFIG";
     } elsif ($stage eq "sky") {
-        $config_file_rule = "PSPHOT.STACK.CONFIG";
+        if ($num_sky_inputs > 1) {
+            $config_file_rule = "PSPHOT.STACK.CONFIG";
+        } else {
+            $config_file_rule = "PSPHOT.SKY.CONFIG";
+        }
     } else {
         &my_die("$stage is not a valid stage", $component, $PS_EXIT_CONFIG_ERROR);
@@ -627,4 +642,24 @@
     return \@file_list;
 }
+sub get_num_sky_inputs {
+    my $sky_id = shift;
+
+    my $command = "$staticskytool -inputs -sky_id $sky_id -simple";
+    $command .= " -dbname $dbname" if $dbname;
+    $command .= " | wc";
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to perform $command: $error_code", $component, $error_code);
+    }
+    my ($num_inputs, $words, $chars) = split " ", (join "", @$stdout_buf);
+    if (!$num_inputs) {
+        $num_inputs = "undefined" if !defined $num_inputs;
+        &my_die("unexpected number of static sky inputs $num_inputs",  $PS_EXIT_PROG_ERROR, $component, $error_code);
+    }
+
+    return $num_inputs;
+}
 
 sub my_die
Index: /branches/czw_branch/20110406/ippScripts/scripts/magic_destreak.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/magic_destreak.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/magic_destreak.pl	(revision 31606)
@@ -364,5 +364,5 @@
 	}
 	else {
-	    print "Did not add sources because the do not appear to exist. This may be an error.\n";
+	    print "Did not add sources because they do not appear to exist. This may be an error.\n";
 	}
         $command .= " -skycelllist $skycell_list" if defined $skycell_list;
Index: /branches/czw_branch/20110406/ippScripts/scripts/receive_file.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/receive_file.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/receive_file.pl	(revision 31606)
@@ -224,6 +224,6 @@
         $stage = 'sky';
         # XXX: This should be skycell, but the distribution code uses exposure
-        $comp_name = 'exposure';
-        $current_component = $comp_name;
+        $comp_name = 'skycell_id';
+#        $current_component = $comp_name;
     } else {
         &my_die( "unexpected run type line found in $filename: $runType\n", $file_id, $PS_EXIT_UNKNOWN_ERROR);
@@ -237,4 +237,13 @@
         $new_workdir_value = "$workdir/$destdir";
     }
+
+    if ($stage eq 'sky') {
+        # the dbinfo file for a skyRun only has one component and it doesn't contain
+        # skycell_id which is the way components are listed in the dirinfo file.
+        my @ids = keys %$components;
+        &my_die( "unexpected number of components scalar @ids found in staticsky dirinfo file\n", $file_id, $PS_EXIT_UNKNOWN_ERROR) if scalar @ids != 1;
+        $current_component = $ids[0];
+    }
+
     my $component_dir;
     if ($current_component) {
Index: /branches/czw_branch/20110406/ippScripts/scripts/register_imfile.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/register_imfile.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/register_imfile.pl	(revision 31606)
@@ -40,5 +40,5 @@
 
 my ($cache, $exp_id, $tmp_class_id, $tmp_exp_name, $uri, $bytes, $md5sum, $dbname, $verbose, $no_update, $no_op, $logfile);
-my ($sunrise, $sunset);
+my ($sunrise, $sunset, $summit_dateobs);
 GetOptions(
     'caches'           => \$cache,
@@ -51,4 +51,5 @@
     'sunrise=s'        => \$sunrise,
     'sunset=s'         => \$sunset,
+    'summit_dateobs=s' => \$summit_dateobs,
     'dbname|d=s'       => \$dbname,    # Database name
     'verbose'          => \$verbose,   # Print to stdout
@@ -181,4 +182,8 @@
 if (uc(&value_for_flag ($cmdflags, "NULL", "-exp_type"))  eq "NULL") { &my_die_for_add ("exp_type  not found", $exp_id, $tmp_exp_name, $tmp_class_id, $uri, $PS_EXIT_CONFIG_ERROR); }
 my $dateobs   = &value_for_flag($cmdflags, 0.0, "-dateobs");
+unless($summit_dateobs) {
+    $summit_dateobs = $dateobs;
+}
+
 my $exp_type  = &value_for_flag($cmdflags, "NULL", "-exp_type");
 
@@ -196,5 +201,5 @@
     $command .= " -data_state full";
 }
-elsif (is_daytime($dateobs,$sunrise,$sunset)) {
+elsif (is_daytime($summit_dateobs,$sunrise,$sunset)) {
     printf STDERR "This is a daytime exposure.\n";
     $command .= " -data_state full";
@@ -267,5 +272,5 @@
 
 if ((abs($burntoolStateCurrent) != $burntoolStateTarget)&&
-    (!is_daytime($dateobs,$sunrise,$sunset))&&
+    (!is_daytime($summit_dateobs,$sunrise,$sunset))&&
     (!is_ccim($tmp_exp_name,$exp_type))) {
     my $mdcParser  = PS::IPP::Metadata::Config->new;
Index: /branches/czw_branch/20110406/ippScripts/scripts/warp_skycell.pl
===================================================================
--- /branches/czw_branch/20110406/ippScripts/scripts/warp_skycell.pl	(revision 31605)
+++ /branches/czw_branch/20110406/ippScripts/scripts/warp_skycell.pl	(revision 31606)
@@ -72,7 +72,9 @@
 
 my ($logDest, $traceDest);
+my $do_stats;
 if ($run_state eq 'new') {
     $logDest = prepare_output("LOG.EXP", $outroot, $skycell_id, 0);
     $traceDest = prepare_output("TRACE.EXP", $outroot, $skycell_id, 1);
+    $do_stats = 1;
 } elsif ($run_state eq 'update')  {
     $logDest = prepare_output("LOG.EXP.UPDATE", $outroot, $skycell_id, 1);
@@ -162,5 +164,8 @@
 my $outputBin1 = prepare_output ("PSWARP.BIN1", $outroot, $skycell_id, 1);
 my $outputBin2 = prepare_output ("PSWARP.BIN2", $outroot, $skycell_id, 1);
-my $outputStats = prepare_output ("SKYCELL.STATS", $outroot, $skycell_id, 1);
+my $outputStats;
+if ($do_stats) {
+    $outputStats = prepare_output ("SKYCELL.STATS", $outroot, $skycell_id, 1) if $do_stats;
+}
 my $configuration;
 
@@ -257,5 +262,4 @@
 # Run pswarp
 my $cmdflags;
-my $do_stats;
 unless ($no_op) {
     my $command = "$pswarp";
@@ -279,5 +283,4 @@
     if ($run_state eq 'new') {
         $command .= " -dumpconfig $configuration";
-        $do_stats = 1;
     } else {
         $command .= " -ipprc $configuration";
Index: /branches/czw_branch/20110406/ippTasks/Makefile.am
===================================================================
--- /branches/czw_branch/20110406/ippTasks/Makefile.am	(revision 31605)
+++ /branches/czw_branch/20110406/ippTasks/Makefile.am	(revision 31606)
@@ -41,5 +41,6 @@
 	lossy_compress.pro \
 	background.pro \
-	diffphot.pro
+	diffphot.pro \
+	lap.pro
 
 other_files = \
Index: /branches/czw_branch/20110406/ippTasks/register.pro
===================================================================
--- /branches/czw_branch/20110406/ippTasks/register.pro	(revision 31605)
+++ /branches/czw_branch/20110406/ippTasks/register.pro	(revision 31606)
@@ -294,4 +294,5 @@
     book getword regPendingImfile $pageName workdir      -var WORKDIR_TEMPLATE
     book getword regPendingImfile $pageName dbname       -var DBNAME
+    book getword regPendingImfile $pageName summit_dateobs -var SUMMIT_DATEOBS
 
     # EXP_TAG is used to generate the unique, but human-readable, filenames
@@ -320,5 +321,5 @@
     # XXX register_imfile.pl differs from the standard script : it does not have an 'outroot' argument, and it does not take '--redirect'
     $run = register_imfile.pl --exp_id $EXP_ID --tmp_class_id $TMP_CLASS_ID --tmp_exp_name $TMP_EXP_NAME --uri $URI --logfile $logfile --bytes $BYTES --md5sum $MD5SUM
-    $run = $run --sunset $sunset --sunrise $sunrise
+    $run = $run --sunset $sunset --sunrise $sunrise --summit_dateobs $SUMMIT_DATEOBS
     add_standard_args run
 
Index: /branches/czw_branch/20110406/ippToPsps/jython/batch.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/batch.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/batch.py	(revision 31606)
@@ -32,5 +32,17 @@
     "../config/2/tables.vot"
     '''
-    def __init__(self, logger, batchType, inputFitsPath="", survey="", useFullTables=False):
+    def __init__(self, 
+                 logger, 
+                 gpc1Db,
+                 ippToPspsDb,
+                 scratchDb,
+                 id,
+                 batchType, 
+                 inputFitsPath="", 
+                 survey="", 
+                 useFullTables=False):
+
+        self.everythingOK = False
+        self.readHeader = False
 
         # set up logging
@@ -40,4 +52,8 @@
 
         # set up class variables
+        self.id = id
+        self.gpc1Db = gpc1Db
+        self.ippToPspsDb = ippToPspsDb
+        self.scratchDb = scratchDb
         self.batchType = batchType;
         self.pspsVoTableFilePath = "../config/" + batchType + "/tables.vot"
@@ -46,4 +62,11 @@
         self.useFullTables = useFullTables
 
+        if self.alreadyProcessed(): return
+
+        # do we have an input file?
+        if self.inputFitsPath != "":
+
+            if not self.readPrimaryHeader(): return
+
         # TODO
         self.tablesToExport = []
@@ -51,9 +74,4 @@
         # open config
         doc = ElementTree(file="config.xml")
-
-        # create Gpc1Db object
-        self.gpc1Db = Gpc1Db(self.logger)
-        self.ippToPspsDb = IppToPspsDb(logger)
-        self.scratchDb = ScratchDb(logger, self.useFullTables)
 
         if self.survey != "":
@@ -88,13 +106,9 @@
         self.dateStr = now.strftime("%Y-%m-%d")
 
-        if self.inputFitsPath != "": 
-            file = open(self.inputFitsPath)
-            self.header = self.parseFitsHeader(file)
-            self.logger.info("Read primary and found " + str(len(self.header)) + " header cards") 
-            # TODO close file?
-
         # create DVO tables if accessing DVO directly
         if not self.useFullTables: self.scratchDb.createDvoTables()
 
+        self.everythingOK = True
+
     '''
     Destructor
@@ -103,4 +117,27 @@
 
         self.logger.debug("Batch destructor")
+
+
+    '''
+    Reads the primary header of the FITS file
+    '''
+    def readPrimaryHeader(self):
+
+        if self.readHeader: return True
+
+        # does it exist?
+        if not os.path.isfile(self.inputFitsPath):
+
+            self.logger.error("Cannot read file at '" + self.inputFitsPath + "'")
+            return False
+
+        file = open(self.inputFitsPath)
+        self.header = self.parseFitsHeader(file)
+        self.logger.info("Read primary header and found " + str(len(self.header)) + " header cards")
+        # TODO close file?
+
+        self.readHeader = True
+
+        return True
 
 
@@ -138,6 +175,8 @@
             file.seek(index + 2880, 0)
             
-        if found != True: self.logger.error("...could not find extension '" + name + "'")
-        else: self.logger.info("...read header at '" + name + "' and found " + str(len(header)) + " header cards") 
+        if found != True: 
+            self.logger.error("...could not read header in extension '" + name + "'")
+            return
+        #else: self.logger.info("...read header at '" + name + "' and found " + str(len(header)) + " header cards") 
 
         return header
@@ -262,9 +301,13 @@
 
         first = True
+
+        self.totalDetections = 0
         for table in tables:
 
-            sql = "SELECT MIN(objID), MAX(objID) FROM " + table
-            rs = self.scratchDb.stmt.executeQuery(sql)
+            sql = "SELECT MIN(objID), MAX(objID), COUNT(objID) FROM " + table
+            rs = self.scratchDb.executeQuery(sql)
             rs.first()
+
+            self.totalDetections = self.totalDetections + rs.getLong(3)
 
             if first:
@@ -276,6 +319,9 @@
 
             first = False
+            rs.close()
 
         self.ippToPspsDb.updateMinMaxObjID(self.batchID, self.minObjID, self.maxObjID)
+        self.logger.info("Total detections = %ld min objID = %ld max objID = %ld" % (self.totalDetections, self.minObjID, self.maxObjID))
+
 
     '''
@@ -313,5 +359,5 @@
          self.pspsTables = stilts.treads(self.pspsVoTableFilePath)
          for table in self.pspsTables:
-             self.logger.info("Creating PSPS table: " + table.name)
+             self.logger.debug("Creating PSPS table: " + table.name)
              table.write(self.scratchDb.url + '#' + table.name)
              self.tablesToExport.append(table.name)
@@ -337,5 +383,5 @@
     Accepts a regular expression filter so not all tables need to be imported
     '''
-    def importIppTables(self, filter):
+    def importIppTables(self, filter=""):
 
       self.logger.info("Attempting to import tables from input FITS file")
@@ -347,12 +393,12 @@
           match = re.match(filter, table.name)
           if not match: continue
-          self.logger.info("   Reading IPP table " + table.name + " from FITS file")
+          self.logger.info("Reading IPP table " + table.name + " from FITS file")
           table = stilts.tpipe(table, cmd='explodeall')
 
           # drop any previous tables before import
-          self.scratchDb.dropTable(table.name)
+          #self.scratchDb.dropTable(table.name)
 
           # IPP FITS files are littered with infinities, so remove these
-          self.logger.info("   Removing Infinity values from all columns")
+          self.logger.debug("Removing Infinity values from all columns")
           table = stilts.tpipe(table, cmd='replaceval -Infinity null *')
           table = stilts.tpipe(table, cmd='replaceval Infinity null *')
@@ -360,10 +406,11 @@
           try:
               table.write(self.scratchDb.url + '#' + table.name)
+              self.scratchDb.killLastConnectionID()
+              count = count + 1
           except:
-              self.logger.exception("   Problem writing table '" + table.name + "' to the database")
-          count = count + 1
+              self.logger.exception("Problem writing table '" + table.name + "' to the database")
+
 
       self.logger.info("Done. Imported %d tables" % count)
-
       self.indexIppTables()
 
@@ -373,8 +420,8 @@
     def exportPspsTablesToFits(self, regex="(.*)"):
 
-        self.logger.info("Replacing NULLs with -999 then exporting all PSPS tables to FITS")
+        self.logger.info("Replacing NULLs with -999, changing tables names using regex: " + regex)
         _tables = []
 
-        self.logger.info("    Selecting database tables")
+        self.logger.info("Selecting database tables")
         for table in self.tablesToExport:
 
@@ -383,6 +430,11 @@
 
            # get everything from table
-           _table = stilts.tread(self.scratchDb.url + '#SELECT * FROM ' + table)
-
+           try:
+               _table = stilts.tread(self.scratchDb.url + '#SELECT * FROM ' + table)
+               self.scratchDb.killLastConnectionID()
+           except:
+               self.logger.exception("Could not read from DB table: " + table)
+               return False
+               
            # replace nulls and empty fields with weird PSPS -999 pseudo-null
            _table = stilts.tpipe(_table, cmd='replaceval "" -999 *')
@@ -395,8 +447,13 @@
            _tables.append(_table)
 
-        self.logger.info("    Writing to FITS file '" + self.outputFitsPath + "'...")
-        stilts.twrites(_tables, self.outputFitsPath, fmt='fits')
-        self.logger.info("    ...done")
-        self.ippToPspsDb.updateProcessed(self.batchID, 1)
+        self.logger.info("Writing to FITS file '" + self.outputFitsPath + "'...")
+        try:
+            stilts.twrites(_tables, self.outputFitsPath, fmt='fits')
+            self.ippToPspsDb.updateProcessed(self.batchID, 1)
+        except:
+            self.logger.exception("Could not write to FITS")
+            return False
+
+        return True
 
     '''
@@ -447,6 +504,24 @@
     '''
     def alreadyProcessed(self):
-           self.logger.info("Not implemented")
-
-
-
+        self.logger.info("Not implemented")
+
+
+    '''
+    Creates and publishes a batch
+    '''
+    def run(self):
+
+        if not self.everythingOK: return
+
+        self.createEmptyPspsTables()
+        self.importIppTables()
+        if self.populatePspsTables():
+            if self.exportPspsTablesToFits():
+                self.writeBatchManifest()
+                self.createTarball()
+                self.publishToDatastore()
+                #self.reportNullsInAllPspsTables(False)
+                #sys.exit()
+        self.logger.info("Finished.")
+
+
Index: /branches/czw_branch/20110406/ippToPsps/jython/detectionbatch.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/detectionbatch.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/detectionbatch.py	(revision 31606)
@@ -6,6 +6,9 @@
 from java.lang import *
 from java.sql import *
+
 from batch import Batch
 from gpc1db import Gpc1Db
+from ipptopspsdb import IppToPspsDb
+from scratchdb import ScratchDb
 
 import logging.config
@@ -19,22 +22,35 @@
     Constructor
     '''
-    def __init__(self, logger, camID, inputFile, test=False, useFullTables=False):
+    def __init__(self, 
+                 logger,
+                 gpc1Db,
+                 ippToPspsDb,
+                 scratchDb,
+                 camID, 
+                 inputFile, 
+                 test=False, 
+                 useFullTables=False):
+
        super(DetectionBatch, self).__init__(
                logger,
+               gpc1Db,
+               ippToPspsDb,
+               scratchDb,
+               camID,
                "detection", 
                inputFile, 
-               "MD04",
-               useFullTables) # TODO
+               "MD04", # TODO
                #"3PI") # TODO
-
-       self.logger.info("DetectionBatch constructor. Creating batch from: '" + inputFile + "'")
-
-       meta = self.gpc1Db.getCameraStageMeta(camID)
-      
-       self.expID = meta[0];
-       self.expName = meta[1];
-       self.distGroup = meta[2];
-
-       self.logger.info("Processing exposure with ID: %d, name: %s and distribution group: %s" % (self.expID, self.expName, self.distGroup))
+               useFullTables)
+
+       if not self.everythingOK: return
+
+       # meta data to the log
+       self.logger.info("New Detection Batch:")
+       self.logger.info("Cam ID:             %d" % self.id)
+       self.logger.info("file:               %s" % inputFile)
+       self.logger.info("Exp ID:             %d" % self.expID)
+       self.logger.info("Exp name:           %s" % self.expName)
+       self.logger.info("Distribution group: %s" % self.distGroup)
 
        # create an output filename, which is {expID}.FITS
@@ -167,5 +183,5 @@
         ," + self.header['PCA2X0Y2'] + " \
         )"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows("FrameMeta", "surveyID", str(self.surveyID))
@@ -184,5 +200,5 @@
         self.scratchDb.dropTable(tableName)
         sql = "CREATE TABLE " + tableName + " LIKE ImageMeta"
-        try: self.scratchDb.stmt.execute(sql)
+        try: self.scratchDb.execute(sql)
         except: pass
 
@@ -310,9 +326,9 @@
                )"
 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
         self.scratchDb.updateFilterID(tableName, self.filter)
         self.scratchDb.updateAllRows(tableName, "calibModNum", str(self.calibModNum))
         self.scratchDb.updateAllRows(tableName, "dataRelease", str(self.dataRelease))
-        self.totalNumPhotoRef = self.totalNumPhotoRef + int(header['NASTRO'])
+        if 'NASTRO' in header: self.totalNumPhotoRef = self.totalNumPhotoRef + int(header['NASTRO'])
         self.scratchDb.replaceNullsInThisColumn(tableName, "polyOrder", "0")
 
@@ -327,5 +343,5 @@
         self.scratchDb.dropTable(tableName)
         sql = "CREATE TABLE " + tableName + " LIKE Detection"
-        try: self.scratchDb.stmt.execute(sql)
+        try: self.scratchDb.execute(sql)
         except: pass
 
@@ -375,10 +391,9 @@
                ,EXT_NSIGMA \
                FROM " + ota + "_psf"
-
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         # set obsTime
         sql = "UPDATE " + tableName + " SET obsTime = %f, assocDate = '%s', activeFlag = 0" % (self.obsTime, self.dateStr)
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
         self.scratchDb.updateAllRows(tableName, "dataRelease", str(self.dataRelease))
         self.scratchDb.updateAllRows(tableName, "historyModNum", "0")
@@ -387,5 +402,5 @@
         self.scratchDb.updateFilterID(tableName, self.filter)
 
-        # now delete bad flux
+        # now delete bad flux and bad chip positions
         self.scratchDb.reportAndDeleteRowsWithNULLS(tableName, "instFlux")
         self.scratchDb.reportAndDeleteRowsWithNULLS(tableName, "peakADU")
@@ -401,5 +416,5 @@
         self.scratchDb.dropTable(tableName)
         sql = "CREATE TABLE " + tableName + " LIKE SkinnyObject"
-        try: self.scratchDb.stmt.execute(sql)
+        try: self.scratchDb.execute(sql)
         except: pass
 
@@ -415,5 +430,5 @@
                ,surveyID \
                FROM Detection_" + ota
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows(tableName, "dataRelease", str(self.dataRelease))
@@ -429,5 +444,5 @@
         self.scratchDb.dropTable(tableName)
         sql = "CREATE TABLE " + tableName + " LIKE ObjectCalColor"
-        try: self.scratchDb.stmt.execute(sql)
+        try: self.scratchDb.execute(sql)
         except: pass
 
@@ -443,5 +458,5 @@
                ,filterID \
                FROM Detection_" + ota
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows(tableName, "calibModNum", str(self.calibModNum))
@@ -484,5 +499,5 @@
 
         imageID = self.scratchDb.getImageIDFromExternID(sourceID, externID)
-        self.logger.info("Updating table '" + table + "' with DVO IDs using imageID = %d" % imageID)
+        self.logger.debug("Updating table '" + table + "' with DVO IDs using imageID = %d" % imageID)
         sql = "UPDATE IGNORE " + table + " AS a, " + self.scratchDb.dvoDetection + " AS b SET \
                a.ippObjID = b.ippObjID, \
@@ -494,5 +509,5 @@
                AND b.imageID = " + str(imageID)
 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
 
@@ -511,4 +526,5 @@
 
         # loop through all OTAs and populate ImageMeta extensions
+        self.logger.info("Reading all fits headers and populating ImageMeta tables")
         for x in range(self.startX, self.endX):
             for y in range(self.startY, self.endY):
@@ -524,4 +540,8 @@
                 # load corresponding header into memory
                 header = self.findAndReadFITSHeader(ota + ".hdr", file)
+                if not header:
+                    self.logger.error("No header found for OTA " + ota)
+                    continue
+
 
                 # store sourceID/imageID combo in Db so DVO can look up later
@@ -578,6 +598,7 @@
 
                 # update ImageMeta with count of detections for this OTA and photoCodeID
-                sql = "UPDATE ImageMeta_" + ota + " SET nDetect = %d, photoCalID = %d" % (self.scratchDb.getRowCount("Detection_" + ota), self.scratchDb.getPhotoCalID(sourceIDs[ota], imageIDs[ota]))
-                self.scratchDb.stmt.execute(sql)
+                sql = "UPDATE ImageMeta_" + ota + " \
+                       SET nDetect = %d, photoCalID = %d" % (self.scratchDb.getRowCount("Detection_" + ota), self.scratchDb.getPhotoCalID(sourceIDs[ota], imageIDs[ota]))
+                self.scratchDb.execute(sql)
 
                 self.populateSkinnyObjectTable(ota)
@@ -603,5 +624,5 @@
         # update FrameMeta with count OTAs in this file and total number of photometric reference sources
         sql = "UPDATE FrameMeta SET nOTA = %d, numPhotoRef = %d" % (otaCount, self.totalNumPhotoRef)
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
         
         return True
@@ -613,5 +634,5 @@
 
         sql = "UPDATE " + tableName + " SET imageID = %d%d%d" % (self.expID, x, y) 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
     '''
@@ -619,4 +640,9 @@
     '''
     def alreadyProcessed(self):
+
+        meta = self.gpc1Db.getCameraStageMeta(self.id)
+        self.expID = meta[0];
+        self.expName = meta[1];
+        self.distGroup = meta[2];
 
         return self.ippToPspsDb.alreadyProcessed("detection", "exp_id", self.expID)
@@ -634,9 +660,31 @@
 
 
+    '''
+    Overriding this method. Filter to only import *.psf extensions
+    '''
+    def importIppTables(self, filter=""):
+       return super(DetectionBatch, self).importIppTables(".*.psf")
+
+
+    '''
+    Overriding this method. Use regex to trim off, eg _XY33 extension
+    '''
+    def exportPspsTablesToFits(self, regex="(.*)"):
+       return super(DetectionBatch, self).exportPspsTablesToFits("([a-zA-Z]+)")
+
+
+# TODO put in config
+useFullTables=True
+testMode=False
+
 logging.config.fileConfig("logging.conf")
 logger = logging.getLogger("detectionbatch")
+logger.setLevel(logging.INFO)
 logger.info("Starting")
 
 gpc1Db = Gpc1Db(logger)
+ippToPspsDb = IppToPspsDb(logger)
+scratchDb = ScratchDb(logger, useFullTables)
+
 camIDs = gpc1Db.getIDsInThisDVODbForThisStage("MD04.V2", "cam")
 logger.info("Found %d exposures" % len(camIDs))
@@ -645,25 +693,16 @@
 for camID in camIDs:
 
-    logger.info("-------------------------------------------------- cam ID: %d" % camID)
+    #if camID < 43764: continue # TODO 
 
     file = gpc1Db.getCameraStageSmf(camID)
-    if not os.path.isfile(file):
-        logger.error("Cannot read file at '" + file)
-        continue
-
-    detectionBatch = DetectionBatch(logger, camID, file, False, True)
-
-    if not detectionBatch.alreadyProcessed():
-
-        detectionBatch.createEmptyPspsTables()
-        detectionBatch.importIppTables(".*.psf")
-        if detectionBatch.populatePspsTables():
-            detectionBatch.exportPspsTablesToFits("([a-zA-Z]+)")
-            detectionBatch.writeBatchManifest()
-            #detectionBatch.reportNullsInAllPspsTables(False)
-            #detectionBatch.createTarball()
-            #detectionBatch.publishToDatastore()
-    
-            i = i+1
-           # if i > 0: sys.exit()
-
+
+    detectionBatch = DetectionBatch(logger,
+                                    gpc1Db,
+                                    ippToPspsDb,
+                                    scratchDb,
+                                    camID, 
+                                    file, 
+                                    testMode, 
+                                    useFullTables)
+    detectionBatch.run()
+
Index: /branches/czw_branch/20110406/ippToPsps/jython/gpc1db.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/gpc1db.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/gpc1db.py	(revision 31606)
@@ -29,4 +29,33 @@
         self.logger.debug("Gpc1Db destructor")
 
+
+    '''
+    TODO
+    '''
+    def getIDsInThisDVODbForThisStageFudge(self):
+
+        sql = "SELECT staticskyRun.sky_id \
+               FROM staticskyInput, staticskyRun, stackRun, staticskyResult \
+               WHERE staticskyRun.sky_id = staticskyInput.sky_id \
+               AND staticskyInput.stack_id = stackRun.stack_id \
+               AND staticskyInput.sky_id = staticskyResult.sky_id \
+               AND staticskyRun.label like 'MD04.staticsky' \
+               AND stackRun.filter like 'i%'"
+
+        try:
+            rs = self.executeQuery(sql)
+        except:
+            self.logger.exception("Can't query for ids in DVO")
+
+        ids = []
+        while (rs.next()):
+            ids.append(rs.getInt(1))
+
+        rs.close()
+
+        self.logger.info("Found %d items in DVO database '" % (len(ids)))
+
+        return ids
+
     '''
     Gets a list of ids in this DVO database for this stage, could be cam or staticsky (so far)
@@ -40,5 +69,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
         except:
             self.logger.exception("Can't query for ids in DVO")
@@ -50,5 +79,5 @@
         rs.close()
 
-        self.logger.debug("Found %d items in DVO database '%s' for stage='%s'" % (len(ids), dvoDb, stage))
+        self.logger.info("Found %d items in DVO database '%s' for stage='%s'" % (len(ids), dvoDb, stage))
 
         return ids
@@ -73,5 +102,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
         except:
             self.logger.exception("Can't query for imageIDs")
@@ -105,5 +134,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             meta.append(rs.getInt(1))
@@ -113,4 +142,5 @@
 
         return meta
+
     '''
     Gets some camera-stage meta data for this cam_id
@@ -127,5 +157,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             meta.append(rs.getInt(1))
@@ -150,5 +180,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
         except:
@@ -171,4 +201,6 @@
             files = glob.glob(path + "/*.cmf")
 
+        if len(files) < 1: return "NULL"
+
         return files[0] # TODO just returning first file - check
 
@@ -186,5 +218,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
         except:
@@ -200,8 +232,6 @@
 
             f=os.popen("neb-ls -p "+path+"%cmf")
-            print "neb-ls -p "+path+"%cmf"
             for i in f.readlines():
                 files.append(i.rstrip())
-                print i.rstrip()
 
         # or not a neb path
@@ -211,2 +241,32 @@
         return files
 
+
+    '''
+    TODO hack to get exposure time for a stack
+    '''
+    def getStackExpTime(self, stackID):
+
+        self.logger.debug("Querying GPC1 for stack exposure time")
+
+        sql = "SELECT SUM(exp_time) * (COUNT(warp_id) - reject_images) / COUNT(warp_id) as EXPTIME \
+               FROM staticskyRun JOIN staticskyInput using(sky_id) \
+               JOIN stackRun using(stack_id) \
+               JOIN stackSumSkyfile using(stack_id) \
+               JOIN stackInputSkyfile using(stack_id) \
+               JOIN warpRun using(warp_id) \
+               JOIN fakeRun using(fake_id) \
+               JOIN camRun using(cam_id) \
+               JOIN chipRun using(chip_id) \
+               JOIN rawExp using(exp_id) \
+               WHERE stack_id = %d" % stackID
+
+        try:
+            rs = self.executeQuery(sql)
+            rs.first()
+            return rs.getInt(1)
+        except:
+            self.logger.exception("Can't query for exposure time")
+
+        return 0.0
+
+
Index: /branches/czw_branch/20110406/ippToPsps/jython/ipptopspsdb.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/ipptopspsdb.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/ipptopspsdb.py	(revision 31606)
@@ -37,5 +37,5 @@
                )"
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
         sql = "SELECT MAX(batch_id) FROM batch"
@@ -44,5 +44,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             batchID = rs.getInt(1)
@@ -64,5 +64,5 @@
                WHERE batch_id = " + str(batchID)
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -75,5 +75,5 @@
                WHERE batch_id = " + str(batchID)
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -86,5 +86,5 @@
                WHERE batch_id = " + str(batchID)
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -101,5 +101,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             if rs.getInt(1) > 0: 
@@ -128,5 +128,5 @@
                )"
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -149,5 +149,5 @@
                )"
 
-        self.stmt.execute(sql)
+        self.execute(sql)
 
 
Index: /branches/czw_branch/20110406/ippToPsps/jython/mysql.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/mysql.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/mysql.py	(revision 31606)
@@ -37,5 +37,15 @@
         self.url = "jdbc:mysql://"+self.dbHost+"/"+self.dbName+"?user="+self.dbUser+"&password="+self.dbPass
         self.con = DriverManager.getConnection(self.url)
-        self.stmt = self.con.createStatement()
+        self.connectionID = self.getLastConnectionID()
+        self.logger.info("MySQL connection to %s with ID %d" % (dbType, self.connectionID))
+
+        #self.stmt = self.con.createStatement()
+
+
+    '''
+    Disconnect from database
+    '''
+    def disconnect(self):
+        self.con.close()
 
     '''
@@ -45,6 +55,31 @@
 
         self.logger.debug("MySql destructor")
-        self.stmt.close()
-        self.con.close()
+        self.disconnect()
+
+    '''
+    Kills the last connection ID, so long as it's not THIS connection ID
+    '''
+    def killLastConnectionID(self):
+   
+        connectionID = self.getLastConnectionID()
+        if connectionID == self.connectionID:
+            self.logger.error("NOT going to kill THIS connection ID")
+            return
+
+        sql = "KILL %d" % connectionID
+        self.execute(sql)
+
+    '''
+    Gets the last connection ID
+    '''
+    def getLastConnectionID(self):
+
+        sql = "SELECT ID \
+               FROM INFORMATION_SCHEMA.PROCESSLIST \
+               WHERE DB='" + self.dbName + "' \
+               ORDER BY ID"
+        rs = self.executeQuery(sql)
+        rs.last()
+        return rs.getInt(1)
 
     '''
@@ -54,5 +89,5 @@
 
         sql = "UPDATE " + table + " SET " + column + " = " + value
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -62,5 +97,5 @@
 
         sql = "DROP TABLE " + table
-        try: self.stmt.execute(sql)
+        try: self.execute(sql)
         except: return
 
@@ -74,5 +109,5 @@
         sql = "ALTER TABLE " + table + " ADD UNIQUE (" + column + ")"
         try:
-            self.stmt.execute(sql)
+            self.execute(sql)
         except: pass
             #self.logger.warn("Index already in place on '" + column + "' for table '" + table + "'")
@@ -82,11 +117,29 @@
     def createIndex(self, table, column):
 
-        self.logger.debug("Creating index on column '"+column+"' for table '"+table+"'")
+        #self.logger.debug("Creating index on column '"+column+"' for table '"+table+"'")
 
         sql = "CREATE INDEX "+table+"_"+column+"_index ON "+table+" ("+column+")"
         try:
-            self.stmt.execute(sql)
+            self.execute(sql)
         except: pass
             #self.logger.warn("Index already in place on '" + column + "' for table '" + table + "'")
+    '''
+    TODO
+    '''
+    def execute(self, sql):
+
+        stmt = self.con.createStatement()
+        stmt.execute(sql)
+        stmt.close()
+
+    '''
+    TODO
+    '''
+    def executeQuery(self, sql):
+
+        stmt = self.con.createStatement()
+        rs = stmt.executeQuery(sql)
+        #stmt.close()
+        return rs
 
     '''
@@ -96,5 +149,5 @@
 
        sql = "SHOW COLUMNS FROM " + tableName
-       rs = self.stmt.executeQuery(sql)
+       rs = self.executeQuery(sql)
        columns = []
        while (rs.next()): columns.append(rs.getString(1))
@@ -109,5 +162,5 @@
 
       sql = "UPDATE " + tableName + " SET " + column + " = " + sub + " WHERE " + column + " IS NULL"
-      self.stmt.execute(sql)
+      self.execute(sql)
 
     '''
@@ -123,5 +176,5 @@
           
           sql = "UPDATE " + tableName + " SET " + column + " = " + sub + " WHERE " + column + " IS NULL"
-          self.stmt.execute(sql)
+          self.execute(sql)
 
     '''
@@ -131,11 +184,11 @@
 
         sql = "SELECT COUNT(*) FROM " + tableName + " WHERE " + columnName + " = " + value
-        rs = self.stmt.executeQuery(sql)
+        rs = self.executeQuery(sql)
         rs.first()
-        nBadFlux = rs.getInt(1)
-        self.logger.info("%d NULL %s values in table %s. Deleting." % (nBadFlux, columnName, tableName))
+        nBad = rs.getInt(1)
+        self.logger.info("%5d NULL %s values in table %s. Deleting." % (nBad, columnName, tableName))
 
         sql="DELETE from " + tableName + " WHERE " + columnName + " = " + value
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -145,11 +198,11 @@
 
         sql = "SELECT COUNT(*) FROM " + tableName + " WHERE " + columnName + " IS NULL"
-        rs = self.stmt.executeQuery(sql)
+        rs = self.executeQuery(sql)
         rs.first()
-        nBadFlux = rs.getInt(1)
-        self.logger.info("%d NULL %s values in table %s. Deleting." % (nBadFlux, columnName, tableName))
+        nBad = rs.getInt(1)
+        self.logger.info("%5d NULL %s values in table %s. Deleting." % (nBad, columnName, tableName))
 
         sql="DELETE from " + tableName + " WHERE " + columnName + " IS NULL"
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -160,5 +213,5 @@
        # first, count rows
        sql = "SELECT COUNT(*) FROM " + tableName
-       rs = self.stmt.executeQuery(sql)
+       rs = self.executeQuery(sql)
        rs.first()
        numRows = rs.getInt(1)
@@ -175,5 +228,5 @@
           
           sql = "SELECT COUNT(*) FROM " + tableName + " WHERE " + column + " IS NULL"
-          rs = self.stmt.executeQuery(sql)
+          rs = self.executeQuery(sql)
           rs.first()
           if rs.getInt(1) == numRows:
@@ -191,5 +244,5 @@
         sql = "SELECT COUNT(*) FROM " + table
         try:
-            rs = self.stmt.executeQuery(sql)  
+            rs = self.executeQuery(sql)  
             rs.first()
             return rs.getInt(1)
Index: /branches/czw_branch/20110406/ippToPsps/jython/scratchdb.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/scratchdb.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/scratchdb.py	(revision 31606)
@@ -45,5 +45,5 @@
         sql = "SELECT surveyID FROM Survey WHERE name = '" + name + "'"
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             return rs.getInt(1)
@@ -61,5 +61,5 @@
         sql = "SELECT flags FROM " + self.dvoMeta + " WHERE sourceID = %s AND externID = %s" % (sourceID, externID)
         try:
-            rs = self.stmt.executeQuery(sql)  
+            rs = self.executeQuery(sql)  
             rs.first()
             flags = rs.getInt(1)
@@ -78,5 +78,5 @@
         sql = "SELECT imageID FROM " + self.dvoMeta + " WHERE sourceID = %s AND externID = %s" % (sourceID, externID)
         try:
-            rs = self.stmt.executeQuery(sql)  
+            rs = self.executeQuery(sql)  
             rs.first()
             imageID = rs.getInt(1)
@@ -95,5 +95,5 @@
         sql = "SELECT photcode FROM " + self.dvoMeta + " WHERE sourceID = %s AND externID = %s" % (sourceID, externID)
         try:
-            rs = self.stmt.executeQuery(sql)  
+            rs = self.executeQuery(sql)  
             rs.first()
             photcode = rs.getInt(1)
@@ -109,5 +109,5 @@
 
         sql = "UPDATE "+table+" AS a, Filter AS b SET a.filterID=b.filterID WHERE b.filterType = '" + filter + "'"
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -123,5 +123,5 @@
                " + str(imageID) + "    \
                )"
-        self.stmt.execute(sql)
+        self.execute(sql)
 
     '''
@@ -131,5 +131,5 @@
 
         sql = "INSERT INTO dvoDone (name) VALUES ('" + name + "')"
-        self.stmt.execute(sql)
+        self.execute(sql)
         
     '''
@@ -141,5 +141,5 @@
 
         try:
-            rs = self.stmt.executeQuery(sql)
+            rs = self.executeQuery(sql)
             rs.first()
             if rs.getInt(1) > 0:
@@ -160,9 +160,9 @@
 
         sql = "DROP TABLE dvoMeta"
-        try: self.stmt.execute(sql)
+        try: self.execute(sql)
         except: pass
         
         sql = "DROP TABLE dvoDetection"
-        try: self.stmt.execute(sql)
+        try: self.execute(sql)
         except: pass
 
@@ -175,5 +175,5 @@
                )"
 
-        try: self.stmt.execute(sql)
+        try: self.execute(sql)
         except: 
             self.logger.error("Unable to create DVO meta-data database table")
@@ -193,5 +193,5 @@
                #INDEX (ippDetectID) \
 
-        try: self.stmt.execute(sql)
+        try: self.execute(sql)
         except: 
             self.logger.error("Unable to create DVO detection database table")
Index: /branches/czw_branch/20110406/ippToPsps/jython/stackbatch.py
===================================================================
--- /branches/czw_branch/20110406/ippToPsps/jython/stackbatch.py	(revision 31605)
+++ /branches/czw_branch/20110406/ippToPsps/jython/stackbatch.py	(revision 31606)
@@ -8,6 +8,9 @@
 from java.sql import *
 
+from batch import Batch
 from gpc1db import Gpc1Db
-from batch import Batch
+from ipptopspsdb import IppToPspsDb
+from scratchdb import ScratchDb
+
 import logging.config
 
@@ -20,7 +23,20 @@
     Constructor
     '''
-    def __init__(self, logger, skyID, inputFile, stackType, useFullTables=False):
+    def __init__(self, 
+                 logger, 
+                 gpc1Db,
+                 ippToPspsDb,
+                 scratchDb,
+                 skyID, 
+                 inputFile, 
+                 stackType, 
+                 useFullTables=False):
+
        super(StackBatch, self).__init__(
                logger,
+               gpc1Db,
+               ippToPspsDb,
+               scratchDb,
+               skyID,
                "stack", 
                inputFile, 
@@ -28,24 +44,18 @@
                useFullTables) # TODO
 
-       self.logger.info("StackBatch constructor. Creating batch from: '" + inputFile + "'")
-
-       self.skyID = skyID
-
-       # get filterID using init table
-       self.filter = self.header['FPA.FILTER']
-       self.filter = self.filter[0:1]
-
-       self.stackType = stackType
-       meta = self.gpc1Db.getStackStageMeta(self.skyID, self.header['FPA.FILTER'])
-       if len(meta) < 1: return
-       self.stackID = meta[0];
-       self.skycell = meta[1];
-
-       # determine skycell from header value
-       #self.skycell = "skycell.34" #= self.header['SKYCELL']
-       self.skycell = self.skycell[8:]
-
-       self.logger.info("Processing stack with ID: %d, type: %s and skycell: %s filter: %s" % (self.stackID, self.stackType, self.skycell, self.filter))
-
+       if not self.everythingOK: return
+
+       self.expTime = gpc1Db.getStackExpTime(self.stackID)
+
+       self.logger.info("got exp time of %d" % self.expTime)
+
+       # meta data to the log
+       self.logger.info("New Stack Batch:")
+       self.logger.info("Sky ID:     %d" % self.id)
+       self.logger.info("File:       %s" % inputFile)
+       self.logger.info("Stack ID:   %d" % self.stackID)
+       self.logger.info("Stack type: %s" % self.stackType)
+       self.logger.info("Skycell:    %s" % self.skycell)
+       self.logger.info("Filter:     %s" % self.filter)
 
        # delete PSPS tables
@@ -58,16 +68,6 @@
        self.scratchDb.dropTable("ObjectCalColor")
 
-       # delete IPP tables
-       #self.scratchDb.dropTable("SkyChip_psf")
-       #self.scratchDb.dropTable("SkyChip_xsrc")
-       #self.scratchDb.dropTable("SkyChip_xfit")
-       #self.scratchDb.dropTable("SkyChip_xrad")
-
-       self.logger.info("Stack type: " + self.safeDictionaryAccess(self.header, self.stackType))
-       # obs time makes no sense except for nightly stacks
-       #if self.header['STK_TYPE'] != "NIGHTLY_STACK": self.header['MJD-OBS'] = "-999"
-
        # create an output filename, which is {filterID}{skycellID}.FITS
-       self.outputFitsFile = "%s%07d.FITS" % (self.filter, int(self.skycell))
+       self.outputFitsFile = "%08d.FITS" % self.stackID
        self.outputFitsPath = "%s/%s" % (self.localOutPath, self.outputFitsFile)
 
@@ -77,5 +77,5 @@
 
        # insert what we know about this stack batch into the stack table
-       self.ippToPspsDb.insertStackMeta(self.batchID, self.skyID, self.stackID, self.filter, self.stackType)
+       self.ippToPspsDb.insertStackMeta(self.batchID, self.id, self.stackID, self.filter, self.stackType)
 
        # insert sourceID/imageID combo so DVO can look it up
@@ -89,5 +89,5 @@
 
         sql = "UPDATE " + table + "  SET stackMetaID=" + str(self.stackID)
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
     '''
@@ -97,5 +97,5 @@
 
         sql = "UPDATE "+table+" AS a, StackType AS b SET a.stackTypeID=b.stackTypeID WHERE b.name = '" + self.stackType + "'"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
 
@@ -148,5 +148,5 @@
         WHERE a.ippDetectID=b.IPP_IDET AND b.PSF_FWHM "+psfCondition
 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
     '''
@@ -196,5 +196,5 @@
         WHERE a.ippDetectID=b.IPP_IDET AND b.MODEL_TYPE = '"+ippModelType+"'"
 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         # sersic fit has an extra parameter
@@ -213,5 +213,5 @@
             WHERE a.ippDetectID=b.IPP_IDET AND b.MODEL_TYPE = '"+ippModelType+"'"
 
-            self.scratchDb.stmt.execute(sql)
+            self.scratchDb.execute(sql)
 
 
@@ -220,4 +220,5 @@
     '''
     def populateStackMeta(self):
+
         self.logger.info("Procesing StackMeta table")
 
@@ -246,5 +247,5 @@
         ," + str(self.scratchDb.getPhotoCalID(self.header['SOURCEID'], self.header['IMAGEID'])) + " \
         ," + self.header['FPA.ZP'] + " \
-        ," + self.header['EXPTIME'] + " \
+        ," + str(self.expTime) + " \
         ,'" + self.safeDictionaryAccess(self.header, 'PSFMODEL') + "' \
         ,'" + self.header['CTYPE1'] + "' \
@@ -261,5 +262,5 @@
         ," + self.header['PC002002'] + " \
         )"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows("StackMeta", "surveyID", str(self.surveyID))
@@ -272,4 +273,5 @@
     '''
     def populateStackDetection(self):
+
         self.logger.info("Procesing StackDetection table")
 
@@ -321,7 +323,7 @@
                ,X_PSF_SIG \
                ,Y_PSF_SIG \
-               ,POW(10.0, (-0.4*PSF_INST_MAG)) / "+self.header['EXPTIME']+" \
-               ,ABS((PSF_INST_MAG_SIG*(POW(10.0, (-0.4*PSF_INST_MAG)) / "+self.header['EXPTIME']+")) / 1.085736) \
-               ,POW(10.0, (-0.4*PEAK_FLUX_AS_MAG)) / "+self.header['EXPTIME']+" \
+               ,POW(10.0, (-0.4*PSF_INST_MAG)) / "+str(self.expTime)+" \
+               ,ABS((PSF_INST_MAG_SIG*(POW(10.0, (-0.4*PSF_INST_MAG)) / "+str(self.expTime)+")) / 1.085736) \
+               ,POW(10.0, (-0.4*PEAK_FLUX_AS_MAG)) / "+str(self.expTime)+" \
                ,SKY \
                ,SKY_SIGMA \
@@ -352,5 +354,5 @@
                FROM SkyChip_psf"
 
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows("StackDetection", "surveyID", str(self.surveyID))
@@ -362,6 +364,17 @@
         self.updateStackTypeID("StackDetection")
         self.updateDvoIDs("StackDetection")
-
-        # now delete bad flux
+        sql = "ALTER TABLE StackDetection ADD PRIMARY KEY (objID, stackDetectID)"
+        self.scratchDb.execute(sql)
+
+        if self.stackType == "DEEP_STACK": 
+
+            #if deep stack and instFlux = null and err not null
+            sql = "UPDATE StackDetection AS a, SkyChip_psf AS b \
+                   SET instFlux = 2*b.PSF_INST_FLUX_SIG \
+                   WHERE instFlux IS NULL \
+                   AND b.PSF_INST_FLUX_SIG IS NOT NULL"
+            self.scratchDb.execute(sql)
+            #    instFlux = 2*PSF_INST_FLUX_SIG
+            
         self.scratchDb.reportAndDeleteRowsWithNULLS("StackDetection", "instFlux")
         self.scratchDb.reportAndDeleteRowsWithNULLS("StackDetection", "objID")
@@ -372,4 +385,5 @@
     '''
     def populateStackApFlx(self):
+
         self.logger.info("Procesing StackApFlx table")
  
@@ -381,16 +395,16 @@
 
         try:
-            self.scratchDb.stmt.execute(sql)
+            self.scratchDb.execute(sql)
         except: return
 
         # TODO temporarily loading 1st convolved fluxes into unconvolved fields
-        self.logger.info("    Adding un-convolved fluxes")
+        self.logger.info("Adding un-convolved fluxes")
         self.updateApFlxs("", "< 7.0")
-        self.logger.info("    Adding 1st convolved fluxes")
+        self.logger.info("Adding 1st convolved fluxes")
         self.updateApFlxs("c1", "< 7.0")
-        self.logger.info("    Adding 2nd convolved fluxes")
+        self.logger.info("Adding 2nd convolved fluxes")
         self.updateApFlxs("c2", "> 7.0")
 
-        self.logger.info("    Adding petrosians for extended sources")
+        self.logger.info("Adding petrosians for extended sources")
         sql = "UPDATE StackApFlx AS a, SkyChip_xsrc AS b SET \
         petRadius=b.PETRO_RADIUS \
@@ -403,5 +417,5 @@
         ,petR90Err=b.PETRO_RADIUS_90_ERR \
         WHERE a.ippDetectID=b.IPP_IDET"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows("StackApFlx", "surveyID", str(self.surveyID))
@@ -413,4 +427,7 @@
         self.updateStackTypeID("StackApFlx")
         self.updateDvoIDs("StackApFlx")
+        self.scratchDb.reportAndDeleteRowsWithNULLS("StackApFlx", "objID")
+        self.deleteDetectionsNotInStackDetection("StackApFlx")
+
 
     '''
@@ -418,4 +435,5 @@
     '''
     def populateStackModelFit(self):
+
         self.logger.info("Procesing StackModelFit table")
 
@@ -423,15 +441,14 @@
         sql = "INSERT INTO StackModelFit (ippDetectID) SELECT DISTINCT IPP_IDET from SkyChip_xfit"
         try:
-            self.scratchDb.stmt.execute(sql)
+            self.scratchDb.execute(sql)
         except:
             return
 
-
         # populate model parameters
-        self.logger.info("    Adding deVaucouleurs fit")
+        self.logger.info("Adding deVaucouleurs fit")
         self.updateModelFit("deV", "PS_MODEL_DEV")
-        self.logger.info("    Adding exponential fit")
+        self.logger.info("Adding exponential fit")
         self.updateModelFit("exp", "PS_MODEL_EXP")
-        self.logger.info("    Adding sersic fit")
+        self.logger.info("Adding sersic fit")
         self.updateModelFit("ser", "PS_MODEL_SERSIC")
 
@@ -444,4 +461,23 @@
         self.updateStackTypeID("StackModelFit")
         self.updateDvoIDs("StackModelFit")
+        self.scratchDb.reportAndDeleteRowsWithNULLS("StackModelFit", "objID")
+        self.deleteDetectionsNotInStackDetection("StackModelFit")
+
+    '''
+    Reports and deletes detections in this table that are not in StackDetection
+    '''
+    def deleteDetectionsNotInStackDetection(self, table):
+
+        sql = "SELECT COUNT(*) FROM " + table + " WHERE ippDetectID NOT IN (SELECT ippDetectID FROM StackDetection)"
+        rs = self.scratchDb.executeQuery(sql)
+        rs.first()
+        nMissing = rs.getInt(1)
+        self.logger.info("%5d detections in %s table that are not in StackDetection. Deleting" % (nMissing, table))
+  
+        if nMissing < 1: return
+        
+        sql = "DELETE FROM " + table + " WHERE ippDetectID NOT IN (SELECT ippDetectID FROM StackDetection)"
+        self.scratchDb.execute(sql)
+       
 
     '''
@@ -449,4 +485,5 @@
     '''
     def populateStackToImage(self):
+
         self.logger.info("Procesing StackToImage table")
 
@@ -457,9 +494,9 @@
                    VALUES (\
                    " + str(self.stackID) + ", " + imageID + ")"
-            self.scratchDb.stmt.execute(sql)
+            self.scratchDb.execute(sql)
 
         # now update StackMeta with correct number of inputs
         sql = "UPDATE StackMeta SET nP2Images = (SELECT COUNT(*) FROM StackToImage)"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
     '''
@@ -467,4 +504,5 @@
     '''
     def populateSkinnyObject(self):
+
         self.logger.info("Procesing SkinnyObject table")
 
@@ -474,8 +512,8 @@
                ) \
                SELECT \
-               objID \
+               DISTINCT objID \
                ,ippObjID \
                FROM StackDetection"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateAllRows("SkinnyObject", "surveyID", str(self.surveyID))
@@ -486,4 +524,5 @@
     '''
     def populateObjectCalColor(self):
+
         self.logger.info("Procesing ObjectCalColor table")
 
@@ -493,8 +532,8 @@
                ) \
                SELECT \
-               objID \
+               DISTINCT objID \
                ,ippObjID \
                FROM StackDetection"
-        self.scratchDb.stmt.execute(sql)
+        self.scratchDb.execute(sql)
 
         self.scratchDb.updateFilterID("ObjectCalColor", self.filter)
@@ -508,5 +547,5 @@
 
         self.logger.info("Altering PSPS tables")
-        self.scratchDb.makeColumnUnique("StackDetection", "objID")
+        #self.scratchDb.makeColumnUnique("StackDetection", "objID")
         self.scratchDb.createIndex("StackDetection", "ippDetectID")
         self.scratchDb.createIndex("StackApFlx", "ippDetectID")
@@ -531,5 +570,5 @@
         imageID = self.scratchDb.getImageIDFromExternID(self.header['SOURCEID'], self.header['IMAGEID'])
 
-        self.logger.info("Updating table '" + table + "' with DVO IDs...")
+        self.logger.debug("Updating table '" + table + "' with DVO IDs...")
         sql = "UPDATE IGNORE " + table + " AS a, dvoDetectionFull AS b SET \
                a.ippObjID = b.ippObjID, \
@@ -539,6 +578,5 @@
                AND b.sourceID = " + self.header['SOURCEID'] + "\
                AND b.imageID = " + str(imageID)
-        self.scratchDb.stmt.execute(sql)
-
+        self.scratchDb.execute(sql)
 
     '''
@@ -553,6 +591,9 @@
         self.populateStackMeta()
         self.populateStackDetection()
-        self.populateStackModelFit()
-        self.populateStackApFlx()
+
+        if self.stackType != "NIGHTLY_STACK": 
+            self.populateStackModelFit()
+            self.populateStackApFlx()
+   
         self.populateStackToImage()
         self.populateSkinnyObject()
@@ -560,5 +601,10 @@
 
         self.setMinMaxObjID(["StackDetection"])
-        
+       
+        if self.totalDetections < 1: 
+
+            self.logger.error("No detections to publish")
+            return False
+
         return True
 
@@ -568,22 +614,49 @@
     def alreadyProcessed(self):
 
-        return self.ippToPspsDb.alreadyProcessed("stack", "stack_id", self.stackID)
+        # sadly, we have to read the FITS primary header first
+        if not self.readPrimaryHeader(): return False
+
+        # get filterID using init table
+        self.filter = self.header['FPA.FILTER']
+        self.filter = self.filter[0:1]
+
+        self.stackType = stackType
+        meta = self.gpc1Db.getStackStageMeta(self.id, self.header['FPA.FILTER'])
+        if len(meta) < 1: return False
+        self.stackID = meta[0];
+        self.skycell = meta[1];
+        self.skycell = self.skycell[8:]
+
+        #return self.ippToPspsDb.alreadyProcessed("stack", "stack_id", self.stackID)
+        return False # TODOI
+
+
+useFullTables=True
 
 logging.config.fileConfig("logging.conf")
 logger = logging.getLogger("stackbatch")
+logger.setLevel(logging.INFO)
 logger.info("Starting")
+
 gpc1Db = Gpc1Db(logger)
-stackType = "NIGHTLY_STACK"
-skyIDs = gpc1Db.getIDsInThisDVODbForThisStage("MD04.Staticsky", "staticsky")
-#skyIDs = gpc1Db.getIDsInThisDVODbForThisStage("MD04.GENE.PSPSDEEP", "staticsky")
-#stackType = "DEEP_STACK"
-#skyIDs = [689]
+ippToPspsDb = IppToPspsDb(logger)
+scratchDb = ScratchDb(logger, useFullTables)
+
+#stackType = "NIGHTLY_STACK"
+#skyIDs = gpc1Db.getIDsInThisDVODbForThisStageFudge()
+#skyIDs = gpc1Db.getIDsInThisDVODbForThisStage("MD04.Staticsky", "staticsky")
+
+stackType = "DEEP_STACK"
+skyIDs = gpc1Db.getIDsInThisDVODbForThisStage("MD04.GENE.PSPSDEEP", "staticsky")
+
+#skyIDs = [942]
 #skyIDs = [299]
 #skyIDs = [302]
 #skyIDs = [8508]
-i = 0
+#i = 0
 for skyID in skyIDs:
-
-    logger.info("-------------------------------------------------- sky ID: %d" % skyID)
+    
+    #if skyID < 1340: continue # nightly
+    #if skyID < 238: continue # deep
 
     cmfFiles = gpc1Db.getStackStageCmfs(skyID)
@@ -591,24 +664,13 @@
     for file in cmfFiles:
 
-        if not os.path.isfile(file):
-            logger.error("Cannot read file at '" + file)
-            continue
-
-        stackBatch = StackBatch(logger, skyID, file, stackType, True)
-
-        if not stackBatch.alreadyProcessed():
-
-            stackBatch.createEmptyPspsTables()
-            stackBatch.importIppTables("")
-            if stackBatch.populatePspsTables():
- 
-                #stackBatch.reportNullsInAllPspsTables(False)
-                stackBatch.exportPspsTablesToFits()
-                stackBatch.writeBatchManifest()
-                #stackBatch.createTarball()
-                #stackBatch.publishToDatastore()
-
-                i = i + 1
-                #if i > 0: sys.exit()
-
-logger.info("Finished")
+        stackBatch = StackBatch(logger,
+                                gpc1Db,
+                                ippToPspsDb,
+                                scratchDb,
+                                skyID, 
+                                file, 
+                                stackType, 
+                                useFullTables)
+
+        stackBatch.run()
+
Index: /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id.sql
===================================================================
--- /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id.sql	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id.sql	(revision 31606)
@@ -3,6 +3,6 @@
 FROM 
      staticskyResult
-join staticSkyRun using (sky_id)
-join staticSkyInput using (stack_id)
+join staticskyRun using (sky_id)
+join staticskyInput using(sky_id)
 JOIN stackRun USING(stack_id)
 
@@ -13,5 +13,5 @@
           ) as foo
      ON sky_id = added_sky_id 
-     AND stage = 'sky'
+     AND stage = 'staticsky'
      -- hook for qualifying the join on the previous_dvodb
      AND %s
Index: /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id_dvo.sql
===================================================================
--- /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id_dvo.sql	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/share/addtool_find_sky_id_dvo.sql	(revision 31606)
@@ -1,4 +1,7 @@
 SELECT staticskyRun.* FROM staticskyResult
 JOIN staticskyRun USING(sky_id)
+join staticskyInput using(sky_id)
+JOIN stackRun USING(stack_id)
+
 WHERE staticskyRun.state = 'full' and staticskyResult.quality = 0
     AND sky_id NOT IN (SELECT sky_id
Index: /branches/czw_branch/20110406/ippTools/share/regtool_pendingimfile.sql
===================================================================
--- /branches/czw_branch/20110406/ippTools/share/regtool_pendingimfile.sql	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/share/regtool_pendingimfile.sql	(revision 31606)
@@ -8,8 +8,10 @@
     newImfile.uri,
     newImfile.bytes,
-    newImfile.md5sum
+    newImfile.md5sum,
+    summitExp.dateobs AS summit_dateobs
 FROM newImfile
 JOIN newExp
     USING(exp_id)
+JOIN summitExp USING(summit_id)
 LEFT JOIN rawImfile
     ON newExp.exp_id = rawImfile.exp_id
Index: /branches/czw_branch/20110406/ippTools/src/addtool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/addtool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/addtool.c	(revision 31606)
@@ -117,5 +117,5 @@
 
     psMetadata *where = psMetadataAlloc();
-    pxcamGetSearchArgs (config, where);
+    //  pxcamGetSearchArgs (config, where);
     PXOPT_COPY_S64(config->args, where,  "-cam_id",    "camRun.cam_id", "==");
     PXOPT_COPY_S64(config->args, where,  "-stack_id",    "stackRun.stack_id", "==");
@@ -123,7 +123,8 @@
     PXOPT_LOOKUP_STR(stage,       config->args, "-stage", false, false);
     if (strcmp(stage, "cam")== 0) {
-
+      pxcamGetSearchArgs (config, where);
     pxAddLabelSearchArgs (config, where, "-label",     "camRun.label", "=="); // define using camRun label
     pxAddLabelSearchArgs (config, where, "-data_group","camRun.data_group", "=="); // define using camRun label
+
     PXOPT_COPY_STR(config->args, where,  "-reduction", "camRun.reduction", "==");
     }
@@ -133,4 +134,5 @@
     pxAddLabelSearchArgs (config, where, "-data_group","stackRun.data_group", "=="); // define using camRun label
     PXOPT_COPY_STR(config->args, where,  "-reduction", "stackRun.reduction", "==");
+    pxAddLabelSearchArgs (config, where, "-filter",     "stackRun.filter", "=="); // define using camRun label
     }
     if (strcmp(stage, "staticsky")== 0) {
@@ -139,4 +141,5 @@
     pxAddLabelSearchArgs (config, where, "-data_group","staticskyRun.data_group", "=="); // define using camRun label
     PXOPT_COPY_STR(config->args, where,  "-reduction", "staticskyyRun.reduction", "==");
+    pxAddLabelSearchArgs (config, where, "-filter",     "stackRun.filter", "=="); // define using camRun label
     }
     
Index: /branches/czw_branch/20110406/ippTools/src/addtoolConfig.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/addtoolConfig.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/addtoolConfig.c	(revision 31606)
@@ -56,4 +56,5 @@
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by camRun label", NULL);
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-data_group", PS_META_DUPLICATE_OK, "search by camRun data_group", NULL);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-filter", PS_META_DUPLICATE_OK, "search by filter", NULL);
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-reduction",          0, "search by camRun reduction class", NULL);
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-destreaked",           0, "only queue destreaked runs", false);
Index: /branches/czw_branch/20110406/ippTools/src/disttool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/disttool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/disttool.c	(revision 31606)
@@ -447,5 +447,5 @@
 
     if (pretend) {
-        if (!ippdbPrintMetadatas(stdout, output, "newdistRuns", true)) {
+        if (!ippdbPrintMetadatas(stdout, output, "newdistRuns", !simple)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
Index: /branches/czw_branch/20110406/ippTools/src/magictool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/magictool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/magictool.c	(revision 31606)
@@ -404,5 +404,6 @@
     PXOPT_LOOKUP_STR(note, config->args, "-set_note", false, false);
     PXOPT_LOOKUP_BOOL(clearfault, config->args, "-clearfault", false);
-
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    
     psString setString = NULL;
     if (fault || clearfault) {
@@ -411,4 +412,7 @@
     if (note) {
         psStringAppend(&setString, ", note = '%s'", note);
+    }
+    if (label) {
+        psStringAppend(&setString, ", label = '%s'", label);
     }
 
Index: /branches/czw_branch/20110406/ippTools/src/magictoolConfig.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/magictoolConfig.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/magictoolConfig.c	(revision 31606)
@@ -81,4 +81,5 @@
     psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-set_state", 0, "set state (required)", NULL);
     psMetadataAddS16(updaterunArgs, PS_LIST_TAIL, "-set_fault", 0, "set fault code", 0);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-set_label", 0, "define label", 0);
     psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-set_note",  0, "define note", NULL);
     psMetadataAddBool(updaterunArgs, PS_LIST_TAIL, "-clearfault",  0, "set fault to zero", NULL);
Index: /branches/czw_branch/20110406/ippTools/src/pstamptool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/pstamptool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/pstamptool.c	(revision 31606)
@@ -843,5 +843,5 @@
     psFree(where);
 
-    psStringAppend(&query, " ORDER BY priority DESC, req_id");
+    psStringAppend(&query, " ORDER BY priority DESC, req_id, job_id");
 
     // treat limit == 0 as "no limit"
@@ -1323,5 +1323,5 @@
     psFree(where);
 
-    psStringAppend(&query, " ORDER BY priority DESC, req_id");
+    psStringAppend(&query, " ORDER BY priority DESC, req_id, dep_id");
 
     // treat limit == 0 as "no limit"
Index: /branches/czw_branch/20110406/ippTools/src/pubtoolConfig.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/pubtoolConfig.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/pubtoolConfig.c	(revision 31606)
@@ -48,5 +48,7 @@
     psMetadataAddStr(defineclientArgs, PS_LIST_TAIL, "-product", 0, "define product (required)", NULL);
     psMetadataAddStr(defineclientArgs, PS_LIST_TAIL, "-workdir", 0, "define workdir (required)", NULL);
+    psMetadataAddS16(defineclientArgs, PS_LIST_TAIL, "-output_format", 0, "define output format", 2);
     psMetadataAddStr(defineclientArgs, PS_LIST_TAIL, "-comment", 0, "define comment", NULL);
+    psMetadataAddStr(defineclientArgs, PS_LIST_TAIL, "-name", 0, "define name", NULL);
     psMetadataAddBool(defineclientArgs, PS_LIST_TAIL, "-unmagicked", 0, "allow unmagicked data?", false);
 
Index: /branches/czw_branch/20110406/ippTools/src/pzgetimfiles.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/pzgetimfiles.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/pzgetimfiles.c	(revision 31606)
@@ -125,5 +125,5 @@
     if (status != 0) {
         // mark the summitExp row as faulted
-        if (!p_psDBRunQueryF(config->dbh, "UPDATE summitExp SET fault = %d WHERE summit_id = %ld", WEXITSTATUS(status), summit_id)) {
+        if (!p_psDBRunQueryF(config->dbh, "UPDATE summitExp SET fault = %d WHERE summit_id = %lld", WEXITSTATUS(status), (long long) summit_id)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
         }
@@ -141,5 +141,5 @@
         // download an "empty" fileset.
         // mark the summitExp row as faulted
-        if (!p_psDBRunQueryF(config->dbh, "UPDATE summitExp SET fault = %d WHERE summit_id = %ld", 250, summit_id)) {
+        if (!p_psDBRunQueryF(config->dbh, "UPDATE summitExp SET fault = %d WHERE summit_id = %lld", 250, (long long) summit_id)) {
                 psError(PS_ERR_UNKNOWN, false, "database error");
         }
Index: /branches/czw_branch/20110406/ippTools/src/pztool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/pztool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/pztool.c	(revision 31606)
@@ -638,5 +638,5 @@
     // set pzDownloadExp.state to 'stop'
     if (!pzDownloadExpSetState(config, summit_id, "stop")) {
-        psError(PS_ERR_UNKNOWN, false, "failed to change pzDownloadExp.state for %ld", summit_id);
+        psError(PS_ERR_UNKNOWN, false, "failed to change pzDownloadExp.state for %lld", (long long) summit_id);
         return false;
     }
@@ -913,5 +913,5 @@
     char *query = "UPDATE pzDownloadExp SET state = '%s' WHERE summit_id = %ld";
     if (!p_psDBRunQueryF(config->dbh, query, state, summit_id)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to change state for %ld", summit_id);
+        psError(PS_ERR_UNKNOWN, false, "failed to change state for %lld", (long long) summit_id);
         return false;
     }
@@ -927,5 +927,5 @@
 
   if (!pzDownloadExpSetState(config,summit_id, state)) {
-    psError(PS_ERR_UNKNOWN, false, "failed to change state for %ld", summit_id);
+    psError(PS_ERR_UNKNOWN, false, "failed to change state for %lld", (long long) summit_id);
     return false;
   }
Index: /branches/czw_branch/20110406/ippTools/src/stacktool.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/stacktool.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/stacktool.c	(revision 31606)
@@ -246,5 +246,6 @@
     PXOPT_COPY_STR(config->args,  where, "-select_data_group",         "warpRun.data_group", "==");
     pxAddLabelSearchArgs (config, where, "-select_label",              "warpRun.label", "LIKE"); // define using warp label
-
+    pxAddLabelSearchArgs (config, where, "-warp_id",                   "warpRun.warp_id", "==");
+    
     // these are used to build the HAVING restriction
     PXOPT_COPY_S32(config->args, having, "-min_num", "num_warp", ">=");
@@ -487,5 +488,5 @@
         // Define the requested association, and insert it if it doesn't already exist
         stackAssociationRow *association = pxStackAssociationDefine(config,stack_id);
-        psS64 sass_id;
+        psS64 sass_id=-1;
         if (!association->sass_id) {
           psTrace("stacktool.association",2,"No required Association found. Adding.");
@@ -508,4 +509,7 @@
           association->sass_id = sass_id;
         }
+	else {
+	  sass_id = association->sass_id;
+	}
         // Insert the map entry for this row.
         stackAssociationMapRow *maprow = stackAssociationMapRowAlloc(sass_id,stack_id);
Index: /branches/czw_branch/20110406/ippTools/src/stacktoolConfig.c
===================================================================
--- /branches/czw_branch/20110406/ippTools/src/stacktoolConfig.c	(revision 31605)
+++ /branches/czw_branch/20110406/ippTools/src/stacktoolConfig.c	(revision 31606)
@@ -91,4 +91,5 @@
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_zpt_obs_max", 0, "define max zero point", NAN);
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_astrom", 0, "define max astrometry rms", NAN);
+    psMetadataAddS64(definebyqueryArgs, PS_LIST_TAIL, "-warp_id", PS_META_DUPLICATE_OK, "include this warp ID (multiple OK)", 0);
     psMetadataAddS32(definebyqueryArgs, PS_LIST_TAIL, "-random", 0, "use this number of random elements", 0);
     psMetadataAddS32(definebyqueryArgs, PS_LIST_TAIL, "-min_num", 0, "minimum number of inputs", 0);
Index: /branches/czw_branch/20110406/ippconfig/gpc1/camera.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/gpc1/camera.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/gpc1/camera.config	(revision 31606)
@@ -165,4 +165,7 @@
 NPIX_INTERCHIP          S32     103794483
 
+# This sets the maximum size for the fwhm_major.  This is roughly 3", and 98.67% of all exposures in the database are less than this.
+MAX_ALLOWED_FWHM          F32         12
+
 # The set of maskbits that should not be set to NAN in "released" images
 # This value is equal to CONV.POOR | STARCORE | SPIKE | SUSPECT  = 0x5280
Index: /branches/czw_branch/20110406/ippconfig/gpc1/ppStack.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/gpc1/ppStack.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/gpc1/ppStack.config	(revision 31606)
@@ -35,4 +35,5 @@
 
 STACK_THREEPI  METADATA
+    PSF.INPUT.MAX   F32     12.0
     OUTPUT.NOCOMP   BOOL    FALSE
     OUTPUT.LOGFLUX  BOOL    TRUE
Index: /branches/czw_branch/20110406/ippconfig/gpc1/psastro.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/gpc1/psastro.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/gpc1/psastro.config	(revision 31606)
@@ -113,5 +113,5 @@
 
 # *** make sure the choice of CATDIR (dvo database) contains the photcodes desired below
-PSASTRO.CATDIR              STR      SYNTH.GRIZY
+PSASTRO.CATDIR              STR      SYNTH.GRIZY 
 DVO.GETSTAR.PHOTCODE        STR      i
 DVO.GETSTAR.MAX.RHO         F32      3000.0
@@ -129,5 +129,5 @@
   FILTER   STR g
   ZEROPT   F32 24.9
-  PHOTCODE STR g_SYNTH
+  PHOTCODE STR g
   GHOST_MAX_MAG                   F32 -20.0
 END
@@ -135,5 +135,5 @@
   FILTER   STR r
   ZEROPT   F32 25.1
-  PHOTCODE STR r_SYNTH
+  PHOTCODE STR r
   GHOST_MAX_MAG                   F32 -20.0
 END
@@ -141,5 +141,5 @@
   FILTER   STR i
   ZEROPT   F32 25.0
-  PHOTCODE STR i_SYNTH
+  PHOTCODE STR i
   GHOST_MAX_MAG                   F32 -25.0
 END
@@ -147,5 +147,5 @@
   FILTER   STR z
   ZEROPT   F32 24.6
-  PHOTCODE STR z_SYNTH
+  PHOTCODE STR z
   GHOST_MAX_MAG                   F32 -25.0
 END
@@ -153,5 +153,5 @@
   FILTER   STR y
   ZEROPT   F32 22.2
-  PHOTCODE STR y_SYNTH
+  PHOTCODE STR y
   GHOST_MAX_MAG                   F32 -25.0
 END
@@ -159,5 +159,5 @@
   FILTER   STR w
   ZEROPT   F32 26.3
-  PHOTCODE STR r_SYNTH
+  PHOTCODE STR r
   GHOST_MAX_MAG                   F32 -20.0
 END
@@ -345,2 +345,6 @@
   PSASTRO.MATCH.FIT.NITER S32    5
 END
+
+LAP_ASTRO METADATA
+  PSASTRO.CATDIR                STR      3PI.20110505.REFCAT
+END
Index: /branches/czw_branch/20110406/ippconfig/gpc1/psphot.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/gpc1/psphot.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/gpc1/psphot.config	(revision 31606)
@@ -20,4 +20,8 @@
 PSF_MODEL              	 	    STR   PS_MODEL_PS1_V1
 PSPHOT.CR.NSIGMA.SOFTEN             F32   0.0025        # Softening parameter for weights in CR stat
+
+PSPHOT.CR.MAX.SIZE                  F32   0.8             # guess for limit on M_minor in pix^2
+PSPHOT.CR.MAX.MAG                   F32  -8.0             # guess for limit on Kron Mag
+PSPHOT.CR.AUTOSCALE                 BOOL  FALSE
 
 PSF.TREND.NX                        S32   3
Index: /branches/czw_branch/20110406/ippconfig/isp/psastro.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/isp/psastro.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/isp/psastro.config	(revision 31606)
@@ -3,10 +3,10 @@
 
 # nominal plate scale (microns / pixel)
-PSASTRO.PIXEL.SCALE    F32  10.0
+PSASTRO.PIXEL.SCALE    F32  1.0
 
 # pmAstromGridMatch:
 PSASTRO.GRID.MIN.ANGLE F32 -2.0
 PSASTRO.GRID.MAX.ANGLE F32 +2.0
-PSASTRO.GRID.DEL.ANGLE F32  0.25
+PSASTRO.GRID.DEL.ANGLE F32  0.5
 PSASTRO.GRID.MIN.SIGMA F32  5.0
 
@@ -14,7 +14,32 @@
 # max grid offset in FP units (microns)
 # use plate-scale to make this in pixels?
-PSASTRO.GRID.OFFSET    F32   10000.
-PSASTRO.GRID.SCALE     F32     500
+PSASTRO.GRID.OFFSET    F32   500.
+PSASTRO.GRID.SCALE     F32      10
 
+PSASTRO.GRID.NREF.MAX S32 2500
+PSASTRO.GRID.NRAW.MAX S32 1500
+
+PSASTRO.PLOT.INST.MAG.MAX F32 -4.0
+PSASTRO.PLOT.INST.MAG.MIN F32 -12.0
+PSASTRO.PLOT.REF.MAG.MIN  F32 +10.0
+PSASTRO.PLOT.REF.MAG.MAX  F32 +20.0
+
+PSASTRO.MIN.INST.MAG.RAW      F32  -12
+PSASTRO.GRID.MIN.INST.MAG.RAW F32  -12
+PSASTRO.MAX.INST.MAG.RAW      F32  -4
+PSASTRO.GRID.MAX.INST.MAG.RAW F32  -4 
+
+ #PSASTRO.MATCH.RADIUS   F32    3
+
+PSASTRO.MATCH.RADIUS.N0 F32    15
+PSASTRO.MATCH.RADIUS.N1 F32    10
+PSASTRO.MATCH.RADIUS.N2 F32    9
+PSASTRO.MATCH.RADIUS.N3 F32    8
+PSASTRO.MATCH.RADIUS.N4 F32    7
+PSASTRO.MATCH.RADIUS.N5 F32    5
+PSASTRO.MATCH.RADIUS.N6 F32    5
+PSASTRO.MATCH.RADIUS.N7 F32    3
+
+PSASTRO.MATCH.FIT.NITER S32    8 
 # these tweak are in FP units (pixels, currently)
 PSASTRO.TWEAK.SCALE     F32      1
@@ -24,5 +49,5 @@
 
 # match radius in pixels for CHIP astrometry
-PSASTRO.MATCH.RADIUS   F32    8
+PSASTRO.MATCH.RADIUS   F32    5
 
 # pmAstromMatchFit
@@ -38,4 +63,7 @@
 PSASTRO.CATDIR         STR      SYNTH.BRIGHT
 PSASTRO.MATCH.LUMFUNC  BOOL     TRUE
+PSASTRO.IGNORE	       STR	SATURATED, DEFECT, SATSTAR, BLEND,FAIL
+
+
 
 
Index: /branches/czw_branch/20110406/ippconfig/isp/psphot.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/isp/psphot.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/isp/psphot.config	(revision 31606)
@@ -1,2 +1,8 @@
+# cosmic ray recipe options - these were tested with o5472i0009o01.201734.ch.191131.cmf
+
+PSPHOT.CR.MAX.SIZE                  F32   0.20           # guess for limit on M_minor in pix^2
+PSPHOT.CR.MAX.MAG                   F32   -7.0             # guess for limit on Kron Mag
+PSPHOT.CR.AUTOSCALE                 BOOL  FALSE
+
 
 # turn these on to see specific outputs
Index: /branches/czw_branch/20110406/ippconfig/recipes/nightly_science.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/recipes/nightly_science.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/recipes/nightly_science.config	(revision 31606)
@@ -203,13 +203,14 @@
   NAME      STR STS
   DISTRIBUTION STR STS
-  # XXX: STS observations are temporarily being taken outside the STS tessellation
-  # switch tess_id from STS.V3 to RINGS
-  TESS      STR RINGS.V3
-  # TESS      STR STS.V3
+  TESS      STR STS.V4
   OBSMODE   STR STS%
-  OBJECT    STR STS%
+#  OBJECT    STR STS%
   STACKABLE BOOL FALSE
   DIFFABLE  BOOL FALSE
   REDUCTION STR STS_DATASET
+  # bump the retention times for the time being
+  CHIP S16 60
+  WARP S16 60
+  DIFF S16 60
 END
 TARGETS METADATA
Index: /branches/czw_branch/20110406/ippconfig/recipes/psastro.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/recipes/psastro.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/recipes/psastro.config	(revision 31606)
@@ -250,2 +250,7 @@
 STS_DATASET METADATA
 END
+
+LAP_ASTRO METADATA
+  
+END
+
Index: /branches/czw_branch/20110406/ippconfig/recipes/psphot.config
===================================================================
--- /branches/czw_branch/20110406/ippconfig/recipes/psphot.config	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/recipes/psphot.config	(revision 31606)
@@ -318,6 +318,6 @@
 PSPHOT.CRMASK.YTEST		    S32   0
 PSPHOT.CRMASK.APPLY		    BOOL  FALSE		  # TEST THIS before enabling.
-PSPHOT.CR.MAX.SIZE		    F32   0.8		  # guess for limit on M_minor in pix^2
-PSPHOT.CR.MAX.MAG		    F32  -8.0		  # guess for limit on Kron Mag
+PSPHOT.CR.MAX.SIZE		    F32   0		  # guess for limit on M_minor in pix^2
+PSPHOT.CR.MAX.MAG		    F32   0		  # guess for limit on Kron Mag
 PSPHOT.CR.AUTOSCALE		    BOOL  FALSE
 
@@ -377,4 +377,58 @@
 END
 
+# Extended source fit parameters
+STACKPHOT_TEST_V1                     METADATA
+  EXTENDED_SOURCE_FITS                BOOL  F  # perform any of the aperture-like measurements?
+  EXTENDED_SOURCE_ANALYSIS            BOOL  F  # perform any of the aperture-like measurements?
+  EXTENDED_SOURCE_SN_LIM              F32   20.0
+  EXTENDED_SOURCE_PETROSIAN           BOOL  TRUE
+  EXTENDED_SOURCE_ANNULI              BOOL  TRUE
+  PSPHOT.STACK.MATCH.PSF.SOURCE       STR   AUTO # which inputs to convolve? (RAW, CNV, AUTO)
+  PSPHOT.STACK.TARGET.PSF.AUTO        BOOL  F    # automatically determine target PSF size?
+  PSPHOT.STACK.USE.RAW                BOOL  F    # perform photometry & morphology analysis on the raw image
+  @PSPHOT.STACK.TARGET.PSF.FWHM       F32   8.0 10.0 # FWHM of target PSF (if NOT AUTO sized; pixels)
+  RADIAL_APERTURES                    BOOL  F    # calculate flux in circular radial apertures?
+  RADIAL_APERTURES_SN_LIM             F32   0.0  # S/N limit for radial aperture calculation
+  OUTPUT.FORMAT                       STR   PS1_V3
+
+  CONSTANT_PHOTOMETRIC_WEIGHTS        BOOL  TRUE
+  POISSON.ERRORS.PHOT.LMM             BOOL  FALSE
+  PSF_APERTURE_SCALE                  F32   4.5
+  PSF_REF_RADIUS                      F32   35
+
+  EXT_FIT_MAX_RADIUS                  F32   50.0
+  PSF_MODEL                           STR   PS_MODEL_QGAUSS 
+  EXT_MODEL                           STR   PS_MODEL_SERSIC
+END
+
+# Extended source fit parameters
+SINGLE_TEST_V1                     METADATA
+  EXTENDED_SOURCE_FITS                BOOL  F  # perform any of the aperture-like measurements?
+  EXTENDED_SOURCE_ANALYSIS            BOOL  F  # perform any of the aperture-like measurements?
+  EXTENDED_SOURCE_SN_LIM              F32   20.0
+  EXTENDED_SOURCE_PETROSIAN           BOOL  TRUE
+  EXTENDED_SOURCE_ANNULI              BOOL  TRUE
+  PSPHOT.STACK.MATCH.PSF.SOURCE       STR   AUTO # which inputs to convolve? (RAW, CNV, AUTO)
+  PSPHOT.STACK.TARGET.PSF.AUTO        BOOL  F    # automatically determine target PSF size?
+  PSPHOT.STACK.USE.RAW                BOOL  F    # perform photometry & morphology analysis on the raw image
+  @PSPHOT.STACK.TARGET.PSF.FWHM       F32   8.0 10.0 # FWHM of target PSF (if NOT AUTO sized; pixels)
+  RADIAL_APERTURES                    BOOL  T    # calculate flux in circular radial apertures?
+  RADIAL_APERTURES_SN_LIM             F32   0.0  # S/N limit for radial aperture calculation
+  OUTPUT.FORMAT                       STR   PS1_SV1
+ #  OUTPUT.FORMAT                       STR   PS1_V3
+
+  # CONSTANT_PHOTOMETRIC_WEIGHTS        BOOL  TRUE
+  # POISSON.ERRORS.PHOT.LMM             BOOL  FALSE
+  CONSTANT_PHOTOMETRIC_WEIGHTS        BOOL  FALSE
+  POISSON.ERRORS.PHOT.LMM             BOOL  TRUE
+
+  PSF_APERTURE_SCALE                  F32   4.5
+  PSF_REF_RADIUS                      F32   35
+
+  EXT_FIT_MAX_RADIUS                  F32   50.0
+  PSF_MODEL                           STR   PS_MODEL_PS1_V1 
+  EXT_MODEL                           STR   PS_MODEL_SERSIC
+END
+
 STACKPHOT_SINGLE    METADATA
   PSPHOT.STACK.USE.RAW                BOOL  F   # since false perform photometry & morphology analysis on the convolved images
Index: /branches/czw_branch/20110406/ippconfig/recipes/reductionClasses.mdc
===================================================================
--- /branches/czw_branch/20110406/ippconfig/recipes/reductionClasses.mdc	(revision 31605)
+++ /branches/czw_branch/20110406/ippconfig/recipes/reductionClasses.mdc	(revision 31606)
@@ -165,4 +165,27 @@
 END
 
+# large area science analysis
+LAP_SCIENCE		METADATA
+	CHIP_PPIMAGE	  STR	  CHIP
+	CHIP_PSPHOT	  STR	  CHIP
+	WARP_PSWARP	  STR	  WARP
+	STACK_PPSTACK	  STR	  STACK
+	STACK_PPSUB	  STR	  STACK
+	STACK_PSPHOT	  STR	  STACK
+	DIFF_PPSUB	  STR	  DIFF
+	DIFF_PSPHOT	  STR	  DIFF
+	JPEG_BIN1	  STR	  PPIMAGE_J1
+	JPEG_BIN2	  STR	  PPIMAGE_J2
+	FAKEPHOT	  STR	  FAKEPHOT
+	ADDSTAR		  STR	  ADDSTAR
+	PSASTRO		  STR	  LAP_ASTRO
+	STACKPHOT_PSPHOT  STR     STACKPHOT
+	STACKPHOT_PPSUB   STR     STACKPHOT
+	STACKPHOT_PPSTACK STR     STACKPHOT
+	STACKPHOT_SINGLE_PSPHOT  STR     STACKPHOT_SINGLE
+	BACKGROUND_PPBACKGROUND	STR	BACKGROUND
+	BACKGROUND_PSWARP	STR	BACKGROUND
+END
+
 DEFAULT_MASKTEST		METADATA
 	CHIP_PPIMAGE	STR	CHIP_MASKTEST
Index: /branches/czw_branch/20110406/ppSim/src/ppSimInsertGalaxies.c
===================================================================
--- /branches/czw_branch/20110406/ppSim/src/ppSimInsertGalaxies.c	(revision 31605)
+++ /branches/czw_branch/20110406/ppSim/src/ppSimInsertGalaxies.c	(revision 31606)
@@ -162,5 +162,5 @@
 	source->psfMag = -2.5*log10(galaxy->flux);
 	source->extMag = -2.5*log10(galaxy->flux);
-	source->errMag = sqrt(Area*PS_SQR(roughNoise) + galaxy->flux) / galaxy->flux;	
+	source->psfMagErr = sqrt(Area*PS_SQR(roughNoise) + galaxy->flux) / galaxy->flux;	
 	
 	// insert the source flux in the image
@@ -173,5 +173,5 @@
 
 	float par8 = (model->params->n == 8) ? model->params->data.F32[7] : 0.0;
-	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", galaxy->x, galaxy->y, flux, 1, source->psfMag, source->errMag, axes.major, axes.minor, axes.theta, par8);
+	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", galaxy->x, galaxy->y, flux, 1, source->psfMag, source->psfMagErr, axes.major, axes.minor, axes.theta, par8);
 
 	psArrayAdd (sources, 100,source);
Index: /branches/czw_branch/20110406/ppSim/src/ppSimInsertStars.c
===================================================================
--- /branches/czw_branch/20110406/ppSim/src/ppSimInsertStars.c	(revision 31605)
+++ /branches/czw_branch/20110406/ppSim/src/ppSimInsertStars.c	(revision 31606)
@@ -121,11 +121,11 @@
 
 	source->psfMag = -2.5*log10(star->flux);
-	source->errMag = sqrt(Area*PS_SQR(roughNoise) + flux) / flux;
+	source->psfMagErr = sqrt(Area*PS_SQR(roughNoise) + flux) / flux;
 	
 	// set the expected model errors
-	model->dparams->data.F32[PM_PAR_I0] = source->errMag * model->params->data.F32[PM_PAR_I0];
+	model->dparams->data.F32[PM_PAR_I0] = source->psfMagErr * model->params->data.F32[PM_PAR_I0];
 
 	float par8 = (model->params->n == 8) ? model->params->data.F32[7] : 0.0;
-	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", star->x, star->y, star->flux, 0, source->psfMag, source->errMag, axes.major, axes.minor, axes.theta, par8);
+	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", star->x, star->y, star->flux, 0, source->psfMag, source->psfMagErr, axes.major, axes.minor, axes.theta, par8);
 
 	// if psfConvolve is TRUE, we will (elsewhere) convolve the image we a PSF
Index: /branches/czw_branch/20110406/ppStack/src/ppStackPrepare.c
===================================================================
--- /branches/czw_branch/20110406/ppStack/src/ppStackPrepare.c	(revision 31605)
+++ /branches/czw_branch/20110406/ppStack/src/ppStackPrepare.c	(revision 31606)
@@ -144,4 +144,5 @@
     int numCols = 0, numRows = 0;   // Size of image
     options->sumExposure = 0.0;
+    int numWithSources = 0;
     for (int i = 0; i < num; i++) {
         pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File of interest
@@ -188,5 +189,5 @@
             pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout with sources
             detections = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.DETECTIONS"); // Sources
-            if (!detections || !detections->allSources) {
+            if (!detections || !detections->allSources || !detections->allSources->n) {
                 psWarning("No detections found for image %d --- rejecting.", i);
                 options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_CAL;
@@ -196,4 +197,5 @@
 
             options->sourceLists->data[i] = psMemIncrRefCounter(detections->allSources);
+            numWithSources++;
         }
 
@@ -230,4 +232,15 @@
             ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
         }
+    }
+    if (numWithSources < 2) {
+        // This can happen if the inputs have been destreaked
+        psErrorStackPrint(stderr, "Not enough inputs have sources");
+        psWarning("No inputs have sources --- suspect bad data quality.");
+        if (options->quality == 0) {
+            options->quality = PPSTACK_ERR_DATA;
+        }
+        psErrorClear();
+        psFree(view);
+        return false;
     }
 
@@ -308,5 +321,21 @@
         psFree(psfs);
         if (!options->psf) {
+#if 1
             psError(psErrorCodeLast(), false, "Unable to determine output PSF.");
+#else
+            // This will repair the problem reproted in ticket 1427 but we aren't yet sure
+            // why ppStackPSF is failing so we are going to continue to fault for now
+            int errorCode = psErrorCodeLast();
+            if (errorCode == PPSTACK_ERR_PSF) {
+                psErrorStackPrint(stderr, "Unable to determine output PSF.");
+                psWarning("Unable to determine output PSF --- suspect bad data quality.");
+                if (options->quality == 0) {
+                    options->quality = errorCode;
+                }
+                psErrorClear();
+            } else {
+                psError(psErrorCodeLast(), false, "Unable to determine output PSF.");
+            }
+#endif // notyet
             psFree(view);
             return false;
Index: /branches/czw_branch/20110406/ppSub/src/ppSubFlagNeighbors.c
===================================================================
--- /branches/czw_branch/20110406/ppSub/src/ppSubFlagNeighbors.c	(revision 31605)
+++ /branches/czw_branch/20110406/ppSub/src/ppSubFlagNeighbors.c	(revision 31606)
@@ -112,5 +112,5 @@
 		  bool positive = !matchRef && (sourceM1->imageID == 1);
 		  positive |= matchRef && (sourceM1->imageID == 2);
-		  float SN1 = isfinite(sourceM1->errMag) ? 1.0 / sourceM1->errMag : NAN;
+		  float SN1 = isfinite(sourceM1->psfMagErr) ? 1.0 / sourceM1->psfMagErr : NAN;
 		  if (positive) {
 		      source->diffStats->SNp = SN1;
@@ -138,6 +138,6 @@
 		  bool positive = !matchRef && (sourceM1->imageID == 1);
 		  positive |= matchRef && (sourceM1->imageID == 2);
-		  float SN1 = isfinite(sourceM1->errMag) ? 1.0 / sourceM1->errMag : NAN;
-		  float SN2 = isfinite(sourceM2->errMag) ? 1.0 / sourceM2->errMag : NAN;
+		  float SN1 = isfinite(sourceM1->psfMagErr) ? 1.0 / sourceM1->psfMagErr : NAN;
+		  float SN2 = isfinite(sourceM2->psfMagErr) ? 1.0 / sourceM2->psfMagErr : NAN;
 		  if (positive) {
 		      source->diffStats->SNp = SN1;
Index: /branches/czw_branch/20110406/ppSub/src/ppSubReadoutPhotometry.c
===================================================================
--- /branches/czw_branch/20110406/ppSub/src/ppSubReadoutPhotometry.c	(revision 31605)
+++ /branches/czw_branch/20110406/ppSub/src/ppSubReadoutPhotometry.c	(revision 31606)
@@ -176,5 +176,5 @@
 
             fprintf(sourceFile, "%f %f %f %f %f %f %f %f %d %f %f %f %f %f\n",
-                    x, y, source->psfMag, source->errMag, chi2, source->crNsigma, source->extNsigma,
+                    x, y, source->psfMag, source->psfMagErr, chi2, source->crNsigma, source->extNsigma,
                     source->pixWeight, source->mode, xMoment, yMoment, xxMoment, xyMoment, yyMoment);
         }
Index: /branches/czw_branch/20110406/psLib/src/fits/psFitsImage.c
===================================================================
--- /branches/czw_branch/20110406/psLib/src/fits/psFitsImage.c	(revision 31605)
+++ /branches/czw_branch/20110406/psLib/src/fits/psFitsImage.c	(revision 31606)
@@ -485,6 +485,9 @@
       double boffset;
       int status;
+      status = 0;
       fits_read_key_dbl(fits->fd, "BOFFSET", &boffset, NULL, &status);
-      outImage = psFitsScaleFromDisk(outImage,boffset);
+      psImage *newImage = psFitsScaleFromDisk(outImage,boffset);
+      psFree (outImage);
+      outImage = newImage;
     }
     psFree(info);
Index: /branches/czw_branch/20110406/psLib/src/imageops/psImageGeomManip.c
===================================================================
--- /branches/czw_branch/20110406/psLib/src/imageops/psImageGeomManip.c	(revision 31605)
+++ /branches/czw_branch/20110406/psLib/src/imageops/psImageGeomManip.c	(revision 31606)
@@ -702,5 +702,5 @@
     } \
     /* note: output(i,j) = input(i+0.5-dx,j+0.5-dy) */ \
-    /* positive dx,dy moves pixel i-dx,j-dy to i,y */ \
+    /* positive dx,dy moves pixel i-dx,j-dy to i,j */ \
     /* also: pixel center is 0.5,0.5 */ \
     for (int row = 0; row < numRows; row++) { \
Index: /branches/czw_branch/20110406/psLib/src/imageops/psImageInterpolate.c
===================================================================
--- /branches/czw_branch/20110406/psLib/src/imageops/psImageInterpolate.c	(revision 31605)
+++ /branches/czw_branch/20110406/psLib/src/imageops/psImageInterpolate.c	(revision 31606)
@@ -31,4 +31,6 @@
 #include "psImageConvolve.h"
 
+# define IS_BILIN_SEPARABLE 0
+
 #include "psImageInterpolate.h"
 
@@ -48,4 +50,5 @@
 };
 
+# if (IS_BILIN_SEPARABLE)
 /// Generate a linear interpolation kernel
 static inline void interpolationKernelBilinear(psF32 *kernel, // Kernel vector to populate
@@ -56,4 +59,19 @@
     kernel[1] = frac;
 }
+# else
+/// Generate a linear interpolation kernel
+static inline void interpolationKernelBilinear(
+    psF32 kernel[kernelSizes[PS_INTERPOLATE_BILINEAR]][kernelSizes[PS_INTERPOLATE_BILINEAR]], // Kernel
+    float xFrac, float yFrac // Fraction of pixel
+    )
+{
+    // (xF*yF, (1-xF)(1-yF) = 1 - xF - yF + xFyF 
+
+    kernel[0][0] = 1.0 - xFrac - yFrac + xFrac*yFrac;
+    kernel[1][0] = yFrac - xFrac*yFrac;
+    kernel[0][1] = xFrac - xFrac*yFrac;
+    kernel[1][1] = xFrac*yFrac;
+}
+# endif
 
 #if 0
@@ -173,7 +191,9 @@
         // Nothing to pre-compute
         break;
+# if (IS_BILIN_SEPARABLE)
       case PS_INTERPOLATE_BILINEAR:
         interpolationKernelBilinear(kernel, frac);
         break;
+# endif
       case PS_INTERPOLATE_GAUSS:
         interpolationKernelGauss(kernel, kernelSizes[mode], 0.5, frac);
@@ -184,4 +204,7 @@
         interpolationKernelLanczos(kernel, kernelSizes[mode], frac);
         break;
+# if (!IS_BILIN_SEPARABLE)
+      case PS_INTERPOLATE_BILINEAR:
+# endif
       case PS_INTERPOLATE_BIQUADRATIC:  // 2D kernel
       default:
@@ -234,5 +257,7 @@
 
     switch (mode) {
+# if (IS_BILIN_SEPARABLE)
       case PS_INTERPOLATE_BILINEAR:
+# endif
       case PS_INTERPOLATE_GAUSS:
       case PS_INTERPOLATE_LANCZOS2:
@@ -258,4 +283,7 @@
         }
         break;
+# if (!IS_BILIN_SEPARABLE)
+      case PS_INTERPOLATE_BILINEAR:
+# endif
       case PS_INTERPOLATE_BIQUADRATIC:
         // 2D kernel, would cost too much memory to pre-calculate
@@ -360,4 +388,11 @@
     int xCentral = floor((X) - 0.5), yCentral = floor((Y) - 0.5); /* Central pixel */ \
     float xFrac = (X) - xCentral - 0.5, yFrac = (Y) - yCentral - 0.5; /* Fraction of pixel */ \
+    bool xExact = fabsf(xFrac) < FLT_EPSILON, yExact = fabsf(yFrac) < FLT_EPSILON; /* Are shifts exact? */ \
+
+// Set up the kernel parameters; defines some useful values
+// EAM : I'm unsure of the right answer here
+#define INTERPOLATE_SETUP_EAM(X, Y)				 \
+    int xCentral = floor((X)), yCentral = floor((Y)); /* Central pixel */ \
+    float xFrac = (X) - xCentral, yFrac = (Y) - yCentral; /* Fraction of pixel */ \
     bool xExact = fabsf(xFrac) < FLT_EPSILON, yExact = fabsf(yFrac) < FLT_EPSILON; /* Are shifts exact? */ \
 
@@ -722,5 +757,5 @@
 }
 
-// Interpolation engine for (separable) interpolation kernels
+// Interpolation engine for (non-separable) interpolation kernels
 static psImageInterpolateStatus interpolateKernel(double *imageValue, double *varianceValue,
                                                   psImageMaskType *maskValue, float x, float y,
@@ -747,6 +782,25 @@
     // Get the appropriate kernels
     psF32 kernel[size][size];
+
+# if (IS_BILIN_SEPARABLE)
     psAssert(mode == PS_INTERPOLATE_BIQUADRATIC, "Mode is %x", mode);
     interpolationKernelBiquadratic(kernel, xFrac, yFrac);
+# else
+    psAssert((mode == PS_INTERPOLATE_BIQUADRATIC) || (mode == PS_INTERPOLATE_BILINEAR), "Mode is %x", mode);
+    if (mode == PS_INTERPOLATE_BIQUADRATIC) {
+	interpolationKernelBiquadratic(kernel, xFrac, yFrac);
+    } else {
+	interpolationKernelBilinear(kernel, xFrac, yFrac);
+    }
+# endif
+
+# if (0)
+    for (int i = 0; i < size; i++) {
+	for (int j = 0; j < size; j++) {
+	    fprintf (stderr, "%f ", kernel[i][j]);
+	}
+	fprintf (stderr, "\n");
+    }
+# endif
 
     float sumKernel = 0.0;              // Sum of the kernel
@@ -908,4 +962,7 @@
         return interpolateKernel(imageValue, varianceValue, maskValue, x, y, interp);
       case PS_INTERPOLATE_BILINEAR:
+# if (!IS_BILIN_SEPARABLE)
+        return interpolateKernel(imageValue, varianceValue, maskValue, x, y, interp);
+# endif
       case PS_INTERPOLATE_GAUSS:
       case PS_INTERPOLATE_LANCZOS2:
Index: /branches/czw_branch/20110406/psLib/src/imageops/psImageMaskOps.c
===================================================================
--- /branches/czw_branch/20110406/psLib/src/imageops/psImageMaskOps.c	(revision 31605)
+++ /branches/czw_branch/20110406/psLib/src/imageops/psImageMaskOps.c	(revision 31606)
@@ -146,6 +146,6 @@
     for (int iy = 0; iy < image->numRows; iy++) { \
         for (int ix = 0; ix < image->numCols; ix++) { \
-            dx = ix + image->col0 - x; \
-            dy = iy + image->row0 - y; \
+            dx = ix + 0.5 + image->col0 - x; \
+            dy = iy + 0.5 + image->row0 - y; \
             r2 = PS_SQR(dx) + PS_SQR(dy); \
             if (r2 <= R2) { \
@@ -197,6 +197,6 @@
     for (int iy = 0; iy < image->numRows; iy++) { \
         for (int ix = 0; ix < image->numCols; ix++) { \
-            dx = ix + image->col0 - x; \
-            dy = iy + image->row0 - y; \
+            dx = ix + 0.5 + image->col0 - x; \
+            dy = iy + 0.5 + image->row0 - y; \
             r2 = PS_SQR(dx) + PS_SQR(dy); \
             if (r2 > R2) { \
Index: /branches/czw_branch/20110406/psModules/src/camera/pmFPAMaskWeight.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/camera/pmFPAMaskWeight.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/camera/pmFPAMaskWeight.c	(revision 31606)
@@ -587,5 +587,7 @@
                 double imageValue, varianceValue; // Image and variance value from interpolation
                 psImageMaskType maskValue = 0; // Mask value from interpolation
-                psImageInterpolateStatus status = psImageInterpolate(&imageValue, &varianceValue, &maskValue, x, y, interp);
+
+		// interpolate to pixel center (index + 0.5)
+                psImageInterpolateStatus status = psImageInterpolate(&imageValue, &varianceValue, &maskValue, x + 0.5, y + 0.5, interp);
                 if (status == PS_INTERPOLATE_STATUS_ERROR || status == PS_INTERPOLATE_STATUS_OFF) {
                     psError(PS_ERR_UNKNOWN, false, "Unable to interpolate readout at %d,%d", x, y);
Index: /branches/czw_branch/20110406/psModules/src/imcombine/pmPSFEnvelope.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/imcombine/pmPSFEnvelope.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/imcombine/pmPSFEnvelope.c	(revision 31606)
@@ -380,5 +380,5 @@
 
         // measure the source moments: tophat windowing, no pixel S/N cutoff
-        if (!pmSourceMoments(source, maxRadius, 0.0, 0.0, maskVal)) {
+        if (!pmSourceMoments(source, maxRadius, 0.0, 0.0, 0.0, maskVal)) {
             // Can't do anything about it; limp along as best we can
             psErrorClear();
Index: /branches/czw_branch/20110406/psModules/src/imcombine/pmSubtractionStamps.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/imcombine/pmSubtractionStamps.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/imcombine/pmSubtractionStamps.c	(revision 31606)
@@ -834,15 +834,21 @@
             }
 
-            psStatsInit (stats);
-            if (!psVectorStats (stats, flux1, NULL, NULL, 0)) {
-                psAbort ("failed to generate stats");
-            }
-            float f1 = stats->sampleMedian;
-
-            psStatsInit (stats);
-            if (!psVectorStats (stats, flux2, NULL, NULL, 0)) {
-                psAbort ("failed to generate stats");
-            }
-            float f2 = stats->sampleMedian;
+            float f1 = NAN;
+            if (flux1->n > 0) {
+                psStatsInit (stats);
+                if (!psVectorStats (stats, flux1, NULL, NULL, 0)) {
+                    psAbort ("failed to generate stats");
+                }
+                f1 = stats->sampleMedian;
+            }
+
+            float f2 = NAN;
+            if (flux2->n > 0) {
+                psStatsInit (stats);
+                if (!psVectorStats (stats, flux2, NULL, NULL, 0)) {
+                    psAbort ("failed to generate stats");
+                }
+                f2 = stats->sampleMedian;
+            }
 
             stamps->window1->kernel[y][x] = f1;
@@ -893,4 +899,14 @@
     float R2 = Sr2 / Sf2;
 
+    if (!isfinite(R1) || !isfinite(R2)) {
+        psError(PM_ERR_STAMPS, true, "Kron Radii are not finite (failure to converge).");
+	psFree (stats);
+	psFree (flux1);
+	psFree (flux2);
+	psFree (norm1);
+	psFree (norm2);
+        return false;
+    }
+
     // Compare the Kron Radii (R1 & R2) to above to the FWHMs : if they are too discrepant, we will need to rescale
     psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii vs FWHMs 1: fwhm: %f, kron %f\n", fwhm1, R1);
@@ -901,4 +917,5 @@
     stamps->normWindow2 = 2.75*R2;
     psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Windows from Kron Radii: %f for 1, %f for 2\n", stamps->normWindow1, stamps->normWindow2);
+
 
     // if the calculated normWindows are too large, we will fall off the stamps.  In this case, we need to try again.
@@ -913,14 +930,4 @@
 	psFree (norm2);
 	return false; 
-    }
-
-    if (!isfinite(R1) || !isfinite(R2)) {
-        psError(PM_ERR_STAMPS, true, "Kron Radii are not finite (failure to converge).");
-	psFree (stats);
-	psFree (flux1);
-	psFree (flux2);
-	psFree (norm1);
-	psFree (norm2);
-        return false;
     }
 
@@ -1197,8 +1204,8 @@
        
 	// fprintf (stderr, "%f,%f : %f %f : %f %f\n", source->peak->xf, source->peak->yf,
-	// source->psfMag, source->apMag, source->psfMag - source->apMag, source->errMag);
+	// source->psfMag, source->apMag, source->psfMag - source->apMag, source->psfMagErr);
 
 	// XXX this is somewhat arbitrary...
-	if (source->errMag > 0.05) continue;
+	if (source->psfMagErr > 0.05) continue;
 	if (fabs(source->psfMag - source->apMag) > 0.5) continue;
 
Index: /branches/czw_branch/20110406/psModules/src/objects/Makefile.am
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/Makefile.am	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/Makefile.am	(revision 31606)
@@ -114,4 +114,5 @@
 	pmTrend2D.h \
 	pmGrowthCurve.h \
+	pmGrowthCurveGenerate.h \
 	pmSourceMatch.h \
 	pmDetEff.h \
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_DEV.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_DEV.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_DEV.c	(revision 31606)
@@ -268,5 +268,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
 	f1 = exp(-pow(z,ALPHA));
         z += DZ;
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_EXP.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_EXP.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_EXP.c	(revision 31606)
@@ -255,5 +255,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         f1 = exp(-sqrt(z));
         z += DZ;
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PGAUSS.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 31606)
@@ -239,5 +239,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         f1 = 1.0 / (1 + z + z*z/2.0 + z*z*z/6.0);
         z += DZ;
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PS1_V1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 31606)
@@ -261,5 +261,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
         z += DZ;
@@ -288,5 +288,4 @@
     if (PAR[PM_PAR_I0] <= 0) return 1.0;
     if (flux >= PAR[PM_PAR_I0]) return 1.0;
-    if (PAR[PM_PAR_7] == 0.0) return powf(PAR[PM_PAR_I0] / flux - 1.0, 1.0 / ALPHA);
 
     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
@@ -296,4 +295,9 @@
     psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
     psF64 sigma = axes.major;
+
+    if (PAR[PM_PAR_7] == 0.0) { 
+        psF32 z =  powf(PAR[PM_PAR_I0] / flux - 1.0, 1.0 / ALPHA);
+        return ( sigma * sqrt (2.0 * z) );
+    }
 
     psF64 limit = flux / PAR[PM_PAR_I0];
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_QGAUSS.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 31606)
@@ -262,5 +262,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA));
         z += DZ;
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_RGAUSS.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 31606)
@@ -251,5 +251,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         f1 = 1.0 / (1 + z + pow(z, PAR[PM_PAR_7]));
         z += DZ;
Index: /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_SERSIC.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_SERSIC.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/models/pmModel_SERSIC.c	(revision 31606)
@@ -316,5 +316,5 @@
     float f0 = 1.0;
     float f1, f2;
-    for (z = DZ; z < 50; z += DZ) {
+    for (z = DZ; z < 150; z += DZ) {
         // f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));
 	f1 = exp(-pow(z,PAR[PM_PAR_7]));
Index: /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.c	(revision 31606)
@@ -73,5 +73,5 @@
     // Fractional pixel radii are not well defined; use integer pixel radii.  Use 1 pixel steps
     // until the scaling factor steps in intervals larger than 1 pixel
-    float Rlin = 1.0 / (fR - 1.0);
+    // float Rlin = 1.0 / (fR - 1.0);
 
     growth->radius = psVectorAllocEmpty (NPTS, PS_DATA_F32);
@@ -79,12 +79,13 @@
     // there will be NPTS radii + a few extras 
     float radius = minRadius;
-    while (radius < Rlin) {
+    while (radius < refRadius) {
 	// fprintf (stderr, "r: %f\n", radius);
-	psVectorAppend (growth->radius, radius);
+	psVectorAppend (growth->radius, radius - 0.001);
 	radius += 1.0;
     }    
+    growth->refBin = growth->radius->n - 1;
     while (radius < maxRadius) {
 	// fprintf (stderr, "r: %f\n", radius);
-	psVectorAppend (growth->radius, radius);
+	psVectorAppend (growth->radius, radius - 0.001);
 	radius *= fR;
 	radius = (int) (radius + 0.5);
@@ -96,6 +97,9 @@
     growth->refRadius = refRadius;
     growth->maxRadius = maxRadius;
-    growth->apLoss = 0.0;
-    growth->fitMag = 0.0;
+    growth->fitMag = NAN;
+    growth->refMag = NAN;
+    growth->apRef  = NAN;
+    growth->apLoss = NAN;
+
     return growth;
 }
Index: /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurve.h	(revision 31606)
@@ -22,6 +22,8 @@
     psF32 maxRadius;
     psF32 fitMag;
+    psF32 refMag;
     psF32 apRef;   // apMag[refRadius]
     psF32 apLoss;  // fitMag - apRef
+    int refBin;
 }
 pmGrowthCurve;
Index: /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 31606)
@@ -50,6 +50,5 @@
 
 #include "pmSourcePhotometry.h"
-
-pmGrowthCurve *pmGrowthCurveForPosition (psImage *image, pmPSF *psf, bool ignore, psImageMaskType maskVal, psImageMaskType markVal, float xc, float yc);
+#include "pmGrowthCurveGenerate.h"
 
 /*****************************************************************************/
@@ -197,5 +196,5 @@
         // mask the given aperture and measure the apMag
         psImageKeepCircle (mask, xc, yc, radius, "OR", markVal);
-        if (!pmSourcePhotometryAper (&apMag, NULL, NULL, model, pixels, NULL, mask, maskVal)) {
+        if (!pmSourcePhotometryAper (NULL, &apMag, NULL, NULL, model, pixels, NULL, mask, maskVal)) {
 	    psFree (growth);
 	    psFree (view);
@@ -226,2 +225,136 @@
     return growth;
 }
+
+# define DEBUG 0
+# if (DEBUG)
+static FILE *fgr = NULL;
+# endif
+
+// we generate the growth curve for the center of the image with the specified psf model
+bool pmGrowthCurveGenerateFromSources (pmReadout *readout, pmPSF *psf, psArray *sources, bool INTERPOLATE_AP, psImageMaskType maskVal, psImageMaskType markVal)
+{
+    PS_ASSERT_PTR_NON_NULL(readout, false);
+    PS_ASSERT_PTR_NON_NULL(readout->image, false);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    pmSourcePhotometryMode photMode = INTERPOLATE_AP ? PM_SOURCE_PHOT_INTERP : 0;
+    
+    // measure the growth curve for each PSF source and average them together
+    psArray *growths = psArrayAllocEmpty (100);
+
+# if (DEBUG)
+    fgr = fopen ("growth.mags.dat", "w");
+# endif
+
+    for (int i = 0; i < sources->n; i++) {
+
+        pmSource *source = sources->data[i];
+
+        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
+
+	pmGrowthCurve *growth = pmGrowthCurveForSource (source, psf, photMode, maskVal, markVal);
+	if (!growth) continue;
+	
+	psArrayAdd (growths, 100, growth);
+	psFree (growth);
+    }
+    psAssert (growths->n, "cannot build growth curve (no valid PSF stars?)");
+
+# if (DEBUG)
+    fclose (fgr);
+# endif
+
+    // just use a simple sample median to get the 'best' value from each growth curve...
+    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
+
+    psVector *values = psVectorAlloc (growths->n, PS_DATA_F32);
+
+    // loop over a range of source fluxes
+    // no need to interpolate since we have forced the object center
+    // to 0.5, 0.5 above
+    for (int i = 0; i < psf->growth->radius->n; i++) {
+
+	// median the values for each radial bin
+	values->n = 0;
+	for (int j = 0; j < growths->n; j++) {
+	    pmGrowthCurve *growth = growths->data[j];
+	    if (!isfinite(growth->apMag->data.F32[i])) continue;
+	    psVectorAppend (values, growth->apMag->data.F32[i] - growth->refMag);
+	}
+	if (values->n == 0) {
+	    psf->growth->apMag->data.F32[i] = NAN;
+	} else {
+	    if (!psVectorStats (stats, values, NULL, NULL, 0)) {
+		psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
+		return false;
+	    }
+	    psf->growth->apMag->data.F32[i] = stats->sampleMedian;
+	}
+    }
+
+    psf->growth->fitMag = psf->growth->apMag->data.F32[psf->growth->radius->n-1];
+    psf->growth->apRef = psVectorInterpolate (psf->growth->radius, psf->growth->apMag, psf->growth->refRadius);
+    psf->growth->apLoss = psf->growth->fitMag - psf->growth->apRef;
+
+    psLogMsg ("psphot.growth", 4, "GrowthCurve : apLoss : %f (fitMag - apMag @ ref : %f - %f)\n", psf->growth->apLoss, psf->growth->fitMag, psf->growth->apRef);
+
+    psFree (growths);
+    psFree (stats);
+    psFree (values);
+
+    return true;
+}
+
+pmGrowthCurve *pmGrowthCurveForSource (pmSource *source, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    float radius;
+
+    assert (psf->growth);
+
+    float minRadius = psf->growth->radius->data.F32[0];
+    pmGrowthCurve *growth = pmGrowthCurveAlloc (minRadius, psf->growth->maxRadius, psf->growth->refRadius);
+
+    // measure the fitMag for this source (for normalization)
+    // pmSourcePhotometryModel (&fitMag, NULL, source->psfModel);
+    growth->fitMag = source->psfMag;
+
+    float xc = source->peak->xf;
+    float yc = source->peak->yf;
+
+    // Loop over the range of radii
+    for (int i = 0; i < growth->radius->n; i++) {
+
+        radius = growth->radius->data.F32[i];
+
+        // mask the given aperture and measure the apMag
+        psImageKeepCircle (source->maskObj, xc, yc, radius, "OR", markVal);
+
+        if (!pmSourceMagnitudes (source, psf, photMode, maskVal, markVal, radius)) {
+	    psFree (growth);
+	    return NULL;
+        }
+
+        // if (!pmSourcePhotometryAper (NULL, &apMag, NULL, NULL, NULL, source->pixels, NULL, source->maskObj, maskVal)) {
+	//     psFree (growth);
+	//     return NULL;
+        // }
+
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+
+	growth->apMag->data.F32[i] = source->apMag;
+    }
+    psAssert(growth->refBin >= 0, "invalid growth reference bin");
+    psAssert(growth->refBin < growth->apMag->n, "invalid growth reference bin");
+    growth->refMag = growth->apMag->data.F32[growth->refBin];
+
+    // Loop over the range of radii
+# if (DEBUG)
+    for (int i = 0; i < growth->radius->n; i++) {
+	fprintf (fgr, "%f %f  %f %f %f %f\n", xc, yc, growth->radius->data.F32[i], growth->apMag->data.F32[i], growth->fitMag, growth->refMag);
+    }
+# endif
+
+    return growth;
+}
Index: /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.h	(revision 31606)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmGrowthCurveGenerate.h	(revision 31606)
@@ -0,0 +1,22 @@
+/* @file  pmGrowthCurveGenerate.h
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-08-24 00:11:02 $
+ * Copyright 2007 IfA, University of Hawaii
+ */
+
+# ifndef PM_GROWTH_CURVE_GENERATE_H
+# define PM_GROWTH_CURVE_GENERATE_H
+
+/// @addtogroup Objects Object Detection / Analysis Functions
+/// @{
+
+bool pmGrowthCurveGenerate (pmReadout *readout, pmPSF *psf, bool ignore, psImageMaskType maskVal, psImageMaskType mark);
+pmGrowthCurve *pmGrowthCurveForPosition (psImage *image, pmPSF *psf, bool ignore, psImageMaskType maskVal, psImageMaskType markVal, float xc, float yc);
+bool pmGrowthCurveGenerateFromSources (pmReadout *readout, pmPSF *psf, psArray *sources, bool INTERPOLATE_AP, psImageMaskType maskVal, psImageMaskType markVal);
+pmGrowthCurve *pmGrowthCurveForSource (pmSource *source, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal, psImageMaskType markVal);
+
+/// @}
+# endif /* PM_GROWTH_CURVE_GENERATE_H */
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPCMdata.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPCMdata.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPCMdata.c	(revision 31606)
@@ -263,8 +263,11 @@
 bool pmPCMupdate(pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model) {
 
-    bool newWindow = (source->pixels->numRows != pcm->modelFlux->numRows) || (source->pixels->numCols != pcm->modelFlux->numCols);
+    bool sameWindow = (source->pixels->numRows == pcm->modelFlux->numRows);
+    sameWindow     &= (source->pixels->numCols == pcm->modelFlux->numCols);
+    sameWindow     &= (source->pixels->col0    == pcm->modelFlux->col0);
+    sameWindow     &= (source->pixels->row0    == pcm->modelFlux->row0);
 
     // re-count the number of unmasked pixels:
-    if (newWindow) {
+    if (!sameWindow) {
 	for (psS32 i = 0; i < source->pixels->numRows; i++) {
 	    for (psS32 j = 0; j < source->pixels->numCols; j++) {
@@ -346,5 +349,5 @@
 
     // has the source pixel window changed?
-    if (newWindow) {
+    if (!sameWindow) {
 
 	// adjust all supporting images:
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPSF.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPSF.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPSF.c	(revision 31606)
@@ -73,7 +73,5 @@
 
     options->type          = 0;
-
     options->stats         = NULL;
-    options->fitOptions    = NULL; // XXX this has to be set before calling pmPSF fit functions
 
     options->psfTrendMode  = PM_TREND_NONE;
@@ -90,5 +88,8 @@
 
     options->chiFluxTrend = true;
-
+    options->fitOptions    = NULL; // XXX this has to be set before calling pmPSF fit functions
+
+    options->fitRadius = NAN;
+    options->apRadius = NAN;
     return options;
 }
@@ -141,4 +142,5 @@
 
     psf->type     = options->type;
+
     psf->chisq    = 0.0;
     psf->ApResid  = 0.0;
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPSF.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPSF.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPSF.h	(revision 31606)
@@ -31,17 +31,28 @@
 struct pmPSF {
     pmModelType type;                   ///< PSF Model in use
-    psArray *params;                    ///< Model parameters (psPolynomial2D)
-    psStats *psfTrendStats;             ///< psf parameter trend clipping stats
-    pmTrend2DMode psfTrendMode;
-    psPolynomial1D *ChiTrend;           ///< Chisq vs flux fit (correction for systematic errors)
-    pmTrend2D *ApTrend;                 ///< ApResid vs (x,y)
-    pmTrend2D *FluxScale;               ///< Flux for PSF at (x,y) for normalization = 1.0
+
+    float chisq;                        ///< PSF goodness statistic (unused??)
     float ApResid;                      ///< apMag - psfMag (for PSF stars)
     float dApResid;                     ///< scatter of ApResid
     float skyBias;                      ///< implied residual sky offset from ApResid fit
     float skySat;                       ///< roll-over of ApResid fit
-    float chisq;                        ///< PSF goodness statistic (unused??)
     int nPSFstars;                      ///< number of stars used to measure PSF
     int nApResid;                       ///< number of stars used to measure ApResid
+
+    bool poissonErrorsPhotLMM;          ///< use poission errors for non-linear model fitting
+    bool poissonErrorsPhotLin;          ///< use poission errors for linear model fitting
+    bool poissonErrorsParams;           ///< use poission errors for model parameter fitting
+
+    pmTrend2D *ApTrend;                 ///< ApResid vs (x,y)
+    pmTrend2D *FluxScale;               ///< Flux for PSF at (x,y) for normalization = 1.0
+    psPolynomial1D *ChiTrend;           ///< Chisq vs flux fit (correction for systematic errors)
+
+    pmGrowthCurve *growth;              ///< apMag vs Radius
+    pmResiduals *residuals;             ///< normalized residual image (no spatial variation)
+
+    psArray *params;                    ///< Model parameters (psPolynomial2D)
+    psStats *psfTrendStats;             ///< psf parameter trend clipping stats
+
+    pmTrend2DMode psfTrendMode;
     int trendNx;
     int trendNy;
@@ -50,9 +61,4 @@
     int fieldXo;
     int fieldYo;
-    bool poissonErrorsPhotLMM;          ///< use poission errors for non-linear model fitting
-    bool poissonErrorsPhotLin;          ///< use poission errors for linear model fitting
-    bool poissonErrorsParams;           ///< use poission errors for model parameter fitting
-    pmGrowthCurve *growth;              ///< apMag vs Radius
-    pmResiduals *residuals;             ///< normalized residual image (no spatial variation)
 };
 
@@ -60,4 +66,5 @@
     pmModelType   type;
     psStats      *stats;                // psfTrend clipping stats
+
     pmTrend2DMode psfTrendMode;
     int           psfTrendNx;
@@ -67,11 +74,14 @@
     int           psfFieldXo;
     int           psfFieldYo;
+
     bool          poissonErrorsPhotLMM; ///< use poission errors for non-linear model fitting
     bool          poissonErrorsPhotLin; ///< use poission errors for linear model fitting
     bool          poissonErrorsParams; ///< use poission errors for model parameter fitting
+
+    bool          chiFluxTrend;         // Fit a trend in Chi2 as a function of flux?
+    pmSourceFitOptions *fitOptions;
+
     float         fitRadius;
     float         apRadius;
-    bool          chiFluxTrend;         // Fit a trend in Chi2 as a function of flux?
-    pmSourceFitOptions *fitOptions;
 } pmPSFOptions;
 
@@ -94,5 +104,4 @@
 double pmPSF_SXYtoModel (psF32 *fittedPar);
 
-bool pmGrowthCurveGenerate (pmReadout *readout, pmPSF *psf, bool ignore, psImageMaskType maskVal, psImageMaskType mark);
 pmPSF *pmPSFBuildSimple (char *typeName, float sxx, float syy, float sxy, ...);
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPSF_IO.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPSF_IO.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPSF_IO.c	(revision 31606)
@@ -63,4 +63,9 @@
 
 bool pmPSFmodelReadPSFClump (psMetadata *analysis, psMetadata *header);
+bool pmPSFmodelRead_ApTrend (pmPSF *psf, pmFPAfile *file);
+bool pmPSFmodelWrite_ApTrend (pmFPAfile *file, pmPSF *psf);
+
+bool pmPSFmodelRead_GrowthCurve (pmPSF *psf, pmFPAfile *file);
+bool pmPSFmodelWrite_GrowthCurve (pmFPAfile *file, pmPSF *psf);
 
 bool pmPSFmodelCheckDataStatusForView (const pmFPAview *view, const pmFPAfile *file)
@@ -197,4 +202,80 @@
         psError(psErrorCodeLast(), false, "Failed to write PSF for chip");
         return false;
+    }
+    return true;
+}
+
+// XXX we save the model term identifiers (item) as S32, but they probably should be more flexible
+bool pmTrend2DtoTable (psArray *table, pmTrend2D *trend, char *label, int item) {
+
+    if (trend == NULL) return true; 
+
+    if (trend->mode == PM_TREND_MAP) {
+	// write the image components into a table: this is needed because they may each be a different size
+	psImageMap *map = trend->map;
+	for (int ix = 0; ix < map->map->numCols; ix++) {
+	    for (int iy = 0; iy < map->map->numRows; iy++) {
+		psMetadata *row = psMetadataAlloc ();
+		psMetadataAddS32 (row, PS_LIST_TAIL, label,        0, "", item);
+		psMetadataAddS32 (row, PS_LIST_TAIL, "X_POWER",    0, "", ix);
+		psMetadataAddS32 (row, PS_LIST_TAIL, "Y_POWER",    0, "", iy);
+		psMetadataAddF32 (row, PS_LIST_TAIL, "VALUE",      0, "", map->map->data.F32[iy][ix]);
+		psMetadataAddF32 (row, PS_LIST_TAIL, "ERROR",      0, "", map->error->data.F32[iy][ix]);
+		psMetadataAddU8  (row, PS_LIST_TAIL, "MASK",       0, "", 0); // no cells are masked
+
+		psArrayAdd (table, 100, row);
+		psFree (row);
+	    }
+	}
+    } else {
+	// write the polynomial components into a table
+	psPolynomial2D *poly = trend->poly;
+	for (int ix = 0; ix <= poly->nX; ix++) {
+	    for (int iy = 0; iy <= poly->nY; iy++) {
+		psMetadata *row = psMetadataAlloc ();
+		psMetadataAddS32 (row, PS_LIST_TAIL, label,        0, "", item);
+		psMetadataAddS32 (row, PS_LIST_TAIL, "X_POWER",    0, "", ix);
+		psMetadataAddS32 (row, PS_LIST_TAIL, "Y_POWER",    0, "", iy);
+		psMetadataAddF32 (row, PS_LIST_TAIL, "VALUE",      0, "", poly->coeff[ix][iy]);
+		psMetadataAddF32 (row, PS_LIST_TAIL, "ERROR",      0, "", poly->coeffErr[ix][iy]);
+		psMetadataAddU8  (row, PS_LIST_TAIL, "MASK",       0, "", poly->coeffMask[ix][iy]);
+
+		psArrayAdd (table, 100, row);
+		psFree (row);
+	    }
+	}
+    }
+    return true;
+}
+
+// extra trend2D elements from a row
+bool pmTrend2DfromTableRow (pmTrend2D *trend, psMetadata *row) {
+
+    bool status = false;
+
+    int xPow = psMetadataLookupS32 (&status, row, "X_POWER");
+    int yPow = psMetadataLookupS32 (&status, row, "Y_POWER");
+
+    if (trend->mode == PM_TREND_MAP) {
+	psImageMap *map = trend->map;
+	assert (map);
+	assert (map->map);
+	assert (map->error);
+	assert (xPow >= 0);
+	assert (yPow >= 0);
+	assert (xPow < map->map->numCols);
+	assert (yPow < map->map->numRows);
+	map->map->data.F32[yPow][xPow]    = psMetadataLookupF32 (&status, row, "VALUE");
+	map->error->data.F32[yPow][xPow]  = psMetadataLookupF32 (&status, row, "ERROR");
+    } else {
+	psPolynomial2D *poly = trend->poly;
+	assert (poly);
+	assert (xPow >= 0);
+	assert (yPow >= 0);
+	assert (xPow <= poly->nX);
+	assert (yPow <= poly->nY);
+	poly->coeff[xPow][yPow]     = psMetadataLookupF32 (&status, row, "VALUE");
+	poly->coeffErr[xPow][yPow]  = psMetadataLookupF32 (&status, row, "ERROR");
+	poly->coeffMask[xPow][yPow] = psMetadataLookupU8  (&status, row, "MASK");
     }
     return true;
@@ -403,9 +484,9 @@
 
             if (trend->mode == PM_TREND_MAP) {
-              nX = trend->map->map->numCols;
-              nY = trend->map->map->numRows;
+		nX = trend->map->map->numCols;
+		nY = trend->map->map->numRows;
             } else {
-              nX = trend->poly->nX;
-              nY = trend->poly->nY;
+		nX = trend->poly->nX;
+		nY = trend->poly->nY;
             }
             snprintf (name, 9, "PAR%02d_NX", i);
@@ -428,45 +509,18 @@
         psMetadataAddF32 (header, PS_LIST_TAIL, "SKY_BIAS", PS_DATA_F32, "sky bias level", psf->skyBias);
 
+	float PSF_APERTURE =  psMetadataLookupF32(&status, roAnalysis, "PSF_APERTURE");
+	if (status) {
+	    psMetadataAddF32 (header, PS_LIST_TAIL, "PSF_APERTURE", PS_DATA_F32, "aperture for psf objects", PSF_APERTURE);
+	}
+	float PSF_FIT_RADIUS =  psMetadataLookupF32(&status, roAnalysis, "PSF_FIT_RADIUS");
+	if (status) {
+	    psMetadataAddF32 (header, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_DATA_F32, "aperture for psf objects", PSF_FIT_RADIUS);
+	}
+
         // build a FITS table of the PSF parameters
         psArray *psfTable = psArrayAllocEmpty (100);
         for (int i = 0; i < nPar; i++) {
             pmTrend2D *trend = psf->params->data[i];
-            if (trend == NULL) continue; // skip unset parameters (eg, XPOS)
-
-            if (trend->mode == PM_TREND_MAP) {
-                // write the image components into a table: this is needed because they may each be a different size
-                psImageMap *map = trend->map;
-                for (int ix = 0; ix < map->map->numCols; ix++) {
-                    for (int iy = 0; iy < map->map->numRows; iy++) {
-                        psMetadata *row = psMetadataAlloc ();
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "MODEL_TERM", 0, "", i);
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "X_POWER",    0, "", ix);
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "Y_POWER",    0, "", iy);
-                        psMetadataAddF32 (row, PS_LIST_TAIL, "VALUE",      0, "", map->map->data.F32[iy][ix]);
-                        psMetadataAddF32 (row, PS_LIST_TAIL, "ERROR",      0, "", map->error->data.F32[iy][ix]);
-                        psMetadataAddU8  (row, PS_LIST_TAIL, "MASK",       0, "", 0); // no cells are masked
-
-                        psArrayAdd (psfTable, 100, row);
-                        psFree (row);
-                    }
-                }
-            } else {
-                // write the polynomial components into a table
-                psPolynomial2D *poly = trend->poly;
-                for (int ix = 0; ix <= poly->nX; ix++) {
-                    for (int iy = 0; iy <= poly->nY; iy++) {
-                        psMetadata *row = psMetadataAlloc ();
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "MODEL_TERM", 0, "", i);
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "X_POWER",    0, "", ix);
-                        psMetadataAddS32 (row, PS_LIST_TAIL, "Y_POWER",    0, "", iy);
-                        psMetadataAddF32 (row, PS_LIST_TAIL, "VALUE",      0, "", poly->coeff[ix][iy]);
-                        psMetadataAddF32 (row, PS_LIST_TAIL, "ERROR",      0, "", poly->coeffErr[ix][iy]);
-                        psMetadataAddU8  (row, PS_LIST_TAIL, "MASK",       0, "", poly->coeffMask[ix][iy]);
-
-                        psArrayAdd (psfTable, 100, row);
-                        psFree (row);
-                    }
-                }
-            }
+	    pmTrend2DtoTable (psfTable, trend, "MODEL_TERM", i);
         }
 
@@ -547,20 +601,17 @@
     }
 
+    if (!pmPSFmodelWrite_ApTrend(file, psf)) {
+	psError(psErrorCodeLast(), false, "Unable to write PSF ApTrend");
+	return false;
+    }
+
+    if (!pmPSFmodelWrite_GrowthCurve(file, psf)) {
+	psError(psErrorCodeLast(), false, "Unable to write PSF Growth Curve");
+	return false;
+    }
+
     // write a representation of the psf model
     {
         psMetadata *header = psMetadataAlloc ();
-
-        if (0) {
-            // set some header keywords to make it clear there are no residuals?
-            if (!psFitsWriteBlank (file->fits, header, residName)) {
-                psError(psErrorCodeLast(), false, "Unable to write blank PSF residuals.");
-                psFree(residName);
-                psFree(header);
-                return false;
-            }
-            psFree (residName);
-            psFree (header);
-            return true;
-        }
 
         int DX = 65;
@@ -651,4 +702,6 @@
 }
 
+
+
 // if this file needs to have a PHU written out, write one
 bool pmPSFmodelWritePHU (const pmFPAview *view, pmFPAfile *file, pmConfig *config)
@@ -934,4 +987,17 @@
     psf->skyBias   = psMetadataLookupF32 (&status, header, "SKY_BIAS");
 
+    if (roAnalysis) {
+	float PSF_APERTURE =  psMetadataLookupF32(&status, header, "PSF_APERTURE");
+	if (status) {
+	    psMetadataAddF32 (roAnalysis, PS_LIST_TAIL, "PSF_APERTURE", PS_DATA_F32, "aperture for psf objects", PSF_APERTURE);
+	}
+	float PSF_FIT_RADIUS =  psMetadataLookupF32(&status, header, "PSF_FIT_RADIUS");
+	if (status) {
+	    psMetadataAddF32 (roAnalysis, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_DATA_F32, "aperture for psf objects", PSF_FIT_RADIUS);
+	}
+    } else {
+	psWarning ("unable to read PSF_APERTURE or PSF_FIT_RADIUS");
+    }
+
     // read the raw table data
     psArray *table = psFitsReadTable (file->fits);
@@ -945,7 +1011,6 @@
     for (int i = 0; i < table->n; i++) {
         psMetadata *row = table->data[i];
+
         int iPar = psMetadataLookupS32 (&status, row, "MODEL_TERM");
-        int xPow = psMetadataLookupS32 (&status, row, "X_POWER");
-        int yPow = psMetadataLookupS32 (&status, row, "Y_POWER");
 
         pmTrend2D *trend = psf->params->data[iPar];
@@ -955,26 +1020,5 @@
         }
 
-        if (trend->mode == PM_TREND_MAP) {
-            psImageMap *map = trend->map;
-            assert (map);
-            assert (map->map);
-            assert (map->error);
-            assert (xPow >= 0);
-            assert (yPow >= 0);
-            assert (xPow < map->map->numCols);
-            assert (yPow < map->map->numRows);
-            map->map->data.F32[yPow][xPow]    = psMetadataLookupF32 (&status, row, "VALUE");
-            map->error->data.F32[yPow][xPow]  = psMetadataLookupF32 (&status, row, "ERROR");
-        } else {
-            psPolynomial2D *poly = trend->poly;
-            assert (poly);
-            assert (xPow >= 0);
-            assert (yPow >= 0);
-            assert (xPow <= poly->nX);
-            assert (yPow <= poly->nY);
-            poly->coeff[xPow][yPow]     = psMetadataLookupF32 (&status, row, "VALUE");
-            poly->coeffErr[xPow][yPow]  = psMetadataLookupF32 (&status, row, "ERROR");
-            poly->coeffMask[xPow][yPow] = psMetadataLookupU8  (&status, row, "MASK");
-        }
+	pmTrend2DfromTableRow(trend, row);
     }
     psFree (header);
@@ -1063,4 +1107,14 @@
     }
 
+    if (!pmPSFmodelRead_ApTrend (psf, file)) {
+	psError(psErrorCodeLast(), false, "Unable to read PSF ApTrend data.");
+	return false;
+    }
+
+    if (!pmPSFmodelRead_GrowthCurve(psf, file)) {
+	psError(psErrorCodeLast(), false, "Unable to read PSF Growth Curve");
+	return false;
+    }
+
     psMetadataAdd (chipAnalysis, PS_LIST_TAIL, "PSPHOT.PSF",     PS_DATA_UNKNOWN,  "psphot psf", psf);
     psFree (psf);
@@ -1070,4 +1124,217 @@
     psFree (header);
 
+    return true;
+}
+
+// write aperture trend to a FITS table
+bool pmPSFmodelWrite_ApTrend (pmFPAfile *file, pmPSF *psf) {
+
+    pmTrend2D *trend = psf->ApTrend;
+    if (trend == NULL) { 
+	psWarning ("no PSF ApTrend to write out, skipping");
+	return true; 
+    }
+
+    // we need to write a header for the table,
+    psMetadata *header = psMetadataAlloc();
+
+    int nX = 0, nY = 0;
+    if (trend->mode == PM_TREND_MAP) {
+	nX = trend->map->map->numCols;
+	nY = trend->map->map->numRows;
+    } else {
+	nX = trend->poly->nX;
+	nY = trend->poly->nY;
+    }
+    psMetadataAddS32 (header, PS_LIST_TAIL, "TREND_NX", 0, "", nX);
+    psMetadataAddS32 (header, PS_LIST_TAIL, "TREND_NY", 0, "", nY);
+    char *modeName = pmTrend2DModeToString (trend->mode);
+    psMetadataAddStr (header, PS_LIST_TAIL, "TREND_MD", 0, "", modeName);
+    psFree (modeName);
+
+    // build a FITS table of the ApTrend (only 1)
+    psArray *table = psArrayAllocEmpty (100);
+    pmTrend2DtoTable (table, trend, "APTREND", 0);
+
+    // write an empty FITS segment if we have no PSF information
+    if (table->n == 0) {
+	psError(PM_ERR_PROG, true, "No PSF data to write.");
+	psFree(table);
+	psFree(header);
+	return false;
+    } 
+
+    psTrace ("pmFPAfile", 5, "writing psf ApTrend data %s\n", "AP_TREND");
+    if (!psFitsWriteTable(file->fits, header, table, "AP_TREND")) {
+	psError(psErrorCodeLast(), false, "Error writing psf table data %s\n", "AP_TREND");
+	psFree(table);
+	psFree(header);
+	return false;
+    }
+
+    psFree (table);
+    psFree (header);
+    return true;
+}
+
+// read aperture trend to a FITS table
+bool pmPSFmodelRead_ApTrend (pmPSF *psf, pmFPAfile *file) {
+
+    bool status;
+
+    // move fits pointer to AP_TREND section
+    // advance to the table data extension
+    if (!psFitsMoveExtNameClean (file->fits, "AP_TREND")) {
+	psWarning ("no Aperture Trend data in PSF file, skipping");
+	return true;
+    }
+
+    psMetadata *header = psFitsReadHeader (NULL, file->fits);
+    if (!header) {
+	psError(psErrorCodeLast(), false, "Unable to read AP_TREND header.");
+	return false;
+    }
+	
+    // read the raw table data
+    psArray *table = psFitsReadTable (file->fits);
+    if (!table) {
+	psError(psErrorCodeLast(), false, "Unable to read AP_TREND table.");
+	psFree(header);
+	return false;
+    }
+
+    // XXX allow user to set this optionally?
+    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
+
+    psImageBinning *binning = psImageBinningAlloc();
+    binning->nXfine = psf->fieldNx;
+    binning->nYfine = psf->fieldNy;
+    binning->nXruff = psMetadataLookupS32 (&status, header, "TREND_NX");
+    binning->nYruff = psMetadataLookupS32 (&status, header, "TREND_NY");
+    psImageBinningSetScale (binning, PS_IMAGE_BINNING_CENTER);
+    char *modeName  = psMetadataLookupStr (&status, header, "TREND_MD");
+    if (!status) {
+	psError(PM_ERR_PROG, true, "inconsistent PSF header: NX & NY defined for AP TREND, but not MD");
+	psFree (header);
+	psFree (stats);
+	psFree (table);
+	return false;
+    }
+    pmTrend2DMode psfTrendMode = pmTrend2DModeFromString (modeName);
+    if (psfTrendMode == PM_TREND_NONE) {
+	psfTrendMode = PM_TREND_POLY_ORD;
+    }
+
+    // measure Trend2D for the current spatial scale
+    pmTrend2D *apTrend = pmTrend2DNoImageAlloc (PM_TREND_MAP, binning, stats);
+
+    // fill in the matching psf->params entries
+    for (int i = 0; i < table->n; i++) {
+	psMetadata *row = table->data[i];
+	pmTrend2DfromTableRow(apTrend, row);
+    }
+    psf->ApTrend = apTrend;
+
+    psFree (binning);
+    psFree (header);
+    psFree (stats);
+    psFree (table);
+    return true;
+}
+
+// write aperture trend to a FITS table
+bool pmPSFmodelWrite_GrowthCurve (pmFPAfile *file, pmPSF *psf) {
+
+    pmGrowthCurve *growth = psf->growth;
+    if (growth == NULL) { 
+	psWarning ("no PSF Growth Curve to write out, skipping");
+	return true; 
+    }
+
+    // we need to write a header for the table,
+    psMetadata *header = psMetadataAlloc();
+
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_MIN_RAD", 0, "", growth->radius->data.F32[0]);
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_MAX_RAD", 0, "", growth->maxRadius);
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_REF_RAD", 0, "", growth->refRadius);
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_AP_LOSS", 0, "", growth->apLoss);
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_AP_REF",  0, "", growth->apRef);
+    psMetadataAddF32 (header, PS_LIST_TAIL, "GROWTH_FIT_MAG", 0, "", growth->fitMag);
+
+    // build a FITS table of the ApTrend (only 1)
+    psArray *table = psArrayAllocEmpty (100);
+    for (int i = 0; i < growth->apMag->n; i++) {
+	psMetadata *row = psMetadataAlloc ();
+	psMetadataAddF32 (row, PS_LIST_TAIL, "RADIUS", 0, "", growth->radius->data.F32[i]);
+	psMetadataAddF32 (row, PS_LIST_TAIL, "AP_MAG", 0, "", growth->apMag->data.F32[i]);
+	psArrayAdd (table, 100, row);
+	psFree (row);
+    }
+
+    // write an empty FITS segment if we have no PSF information
+    if (table->n == 0) {
+	psError(PM_ERR_PROG, true, "No PSF data to write.");
+	psFree(table);
+	psFree(header);
+	return false;
+    } 
+
+    psTrace ("pmFPAfile", 5, "writing psf Growth Curve data %s\n", "GROWTH_CURVE");
+    if (!psFitsWriteTable(file->fits, header, table, "GROWTH_CURVE")) {
+	psError(psErrorCodeLast(), false, "Error writing psf table data %s\n", "GROWTH_CURVE");
+	psFree(table);
+	psFree(header);
+	return false;
+    }
+
+    psFree (table);
+    psFree (header);
+    return true;
+}
+
+// read aperture trend to a FITS table
+bool pmPSFmodelRead_GrowthCurve (pmPSF *psf, pmFPAfile *file) {
+
+    bool status;
+
+    // move fits pointer to AP_TREND section
+    // advance to the table data extension
+    if (!psFitsMoveExtNameClean (file->fits, "GROWTH_CURVE")) {
+	psWarning ("no Growth Curve data in PSF file, skipping");
+	return true;
+    }
+
+    psMetadata *header = psFitsReadHeader (NULL, file->fits);
+    if (!header) {
+	psError(psErrorCodeLast(), false, "Unable to read GROWTH_CURVE header.");
+	return false;
+    }
+	
+    // read the raw table data
+    psArray *table = psFitsReadTable (file->fits);
+    if (!table) {
+	psError(psErrorCodeLast(), false, "Unable to read GROWTH_CURVE table.");
+	psFree(header);
+	return false;
+    }
+
+    float minRadius = psMetadataLookupF32 (&status, header, "GROWTH_MIN_RAD"); if (!status) return false;
+    float maxRadius = psMetadataLookupF32 (&status, header, "GROWTH_MAX_RAD"); if (!status) return false;
+    float refRadius = psMetadataLookupF32 (&status, header, "GROWTH_REF_RAD"); if (!status) return false;
+
+    psf->growth = pmGrowthCurveAlloc(minRadius, maxRadius, refRadius);
+
+    psf->growth->apLoss = psMetadataLookupF32 (&status, header, "GROWTH_AP_LOSS"); if (!status) return false;
+    psf->growth->apRef  = psMetadataLookupF32 (&status, header, "GROWTH_AP_REF"); if (!status) return false;
+    psf->growth->fitMag = psMetadataLookupF32 (&status, header, "GROWTH_FIT_MAG"); if (!status) return false;
+
+    // fill in the matching psf->params entries
+    for (int i = 0; i < table->n; i++) {
+	psMetadata *row = table->data[i];
+	psf->growth->apMag->data.F32[i] = psMetadataLookupF32 (&status, row, "AP_MAG"); if (!status) return false;
+    }
+
+    psFree (header);
+    psFree (table);
     return true;
 }
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPSFtryFitPSF.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPSFtryFitPSF.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPSFtryFitPSF.c	(revision 31606)
@@ -122,5 +122,5 @@
         psfTry->fitMag->data.F32[i] = source->psfMag;
         psfTry->metric->data.F32[i] = source->apMag - source->psfMag;
-        psfTry->metricErr->data.F32[i] = source->errMag;
+        psfTry->metricErr->data.F32[i] = source->psfMagErr;
 
 	// XXX this did not work: modifies shape of psf too much
@@ -131,5 +131,5 @@
 		 source->peak->xf, source->peak->yf, 
 		 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS], 
-		 source->psfMag, source->apMag, source->errMag,
+		 source->psfMag, source->apMag, source->psfMagErr,
 		 source->modelPSF->params->data.F32[PM_PAR_I0], 
 		 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.c	(revision 31606)
@@ -150,4 +150,8 @@
     tmp->x = x;
     tmp->y = y;
+    tmp->xf = x;
+    tmp->yf = y;
+    tmp->dx = NAN;
+    tmp->dy = NAN;
     tmp->detValue      	 = value;
     tmp->rawFlux       	 = value; // set this by default: it is up to the user to supply a better value
@@ -155,7 +159,4 @@
     tmp->smoothFlux    	 = value; // set this by default: it is up to the user to supply a better value
     tmp->smoothFluxStdev = NAN;
-    // tmp->SN = 0;
-    tmp->xf = x;
-    tmp->yf = y;
     tmp->assigned = false;
     tmp->type = type;
@@ -166,4 +167,24 @@
     psTrace("psModules.objects", 10, "---- %s() end ----\n", __func__);
     return(tmp);
+}
+
+// copy to an already allocated peak
+bool pmPeakCopy(pmPeak *out, pmPeak *in)
+{
+    out->x  		 = in->x;
+    out->y  		 = in->y;
+    out->xf 		 = in->xf;
+    out->yf 		 = in->yf;
+    out->dx 		 = in->dx;
+    out->dy 		 = in->dy;
+    out->detValue      	 = in->detValue;
+    out->rawFlux       	 = in->rawFlux;
+    out->rawFluxStdev  	 = in->rawFluxStdev;
+    out->smoothFlux    	 = in->smoothFlux;
+    out->smoothFluxStdev = in->smoothFluxStdev;
+    out->assigned        = in->assigned;
+    out->type      	 = in->type;
+
+    return true;
 }
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmPeaks.h	(revision 31606)
@@ -69,5 +69,4 @@
     float smoothFlux;                   ///< peak flux in smoothed signal image
     float smoothFluxStdev;              ///< peak stdev in smoothed signal image
-    // float SNestimated;                  ///< S/N estimated from the detection image
     bool assigned;                      ///< is peak assigned to a source?
     pmPeakType type;                    ///< Description of peak.
@@ -89,4 +88,6 @@
 
 bool psMemCheckPeak(psPtr ptr);
+
+bool pmPeakCopy(pmPeak *out, pmPeak *in);
 
 /** pmPeaksInVector()
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSource.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSource.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSource.c	(revision 31606)
@@ -116,5 +116,4 @@
     source->psfImage = NULL;
     source->moments = NULL;
-    source->blends = NULL;
     source->modelPSF = NULL;
     source->modelEXT = NULL;
@@ -124,18 +123,11 @@
     source->mode2 = PM_SOURCE_MODE_DEFAULT;
     source->tmpFlags = 0;
-    source->extpars = NULL;
-    source->diffStats = NULL;
-    source->radialAper = NULL;
-    source->parent = NULL;
-
-    source->region = psRegionSet(NAN, NAN, NAN, NAN);
-    psMemSetDeallocator(source, (psFreeFunc) sourceFree);
 
     // default values are NAN
     source->psfMag     	     = NAN;
+    source->psfMagErr 	     = NAN;
     source->psfFlux    	     = NAN;
     source->psfFluxErr 	     = NAN;
     source->extMag 	     = NAN;    
-    source->errMag 	     = NAN;
     source->apMag  	     = NAN;
     source->apMagRaw  	     = NAN;
@@ -143,6 +135,5 @@
     source->apFlux    	     = NAN;
     source->apFluxErr 	     = NAN; 
-    source->sky    	     = NAN;
-    source->skyErr 	     = NAN;    
+
     source->pixWeightNotBad  = NAN;
     source->pixWeightNotPoor = NAN;
@@ -151,4 +142,16 @@
     source->crNsigma         = NAN;
     source->extNsigma        = NAN;
+    source->sky    	     = NAN;
+    source->skyErr 	     = NAN;    
+
+    source->region = psRegionSet(NAN, NAN, NAN, NAN);
+    source->blends = NULL;
+    source->extpars = NULL;
+    source->diffStats = NULL;
+    source->radialAper = NULL;
+    source->parent = NULL;
+    source->imageID = -1;
+
+    psMemSetDeallocator(source, (psFreeFunc) sourceFree);
 
     psTrace("psModules.objects", 10, "---- end ----\n");
@@ -172,11 +175,5 @@
     if (in->peak != NULL) {
         source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->detValue, in->peak->type);
-        source->peak->xf = in->peak->xf;
-        source->peak->yf = in->peak->yf;
-        source->peak->rawFlux         = in->peak->rawFlux;
-        source->peak->rawFluxStdev    = in->peak->rawFluxStdev;
-        source->peak->smoothFlux      = in->peak->smoothFlux;
-        source->peak->smoothFluxStdev = in->peak->smoothFluxStdev;
-        // source->peak->SN = in->peak->SN;
+	pmPeakCopy(source->peak, in->peak);
     }
 
@@ -195,9 +192,31 @@
 
     // the maskObj is a unique mask array; create a new mask image
-    source->maskObj = in->maskObj ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
-
-    source->type = in->type;
-    source->mode = in->mode;
-    source->imageID = in->imageID;
+    source->maskObj = in->maskObj   ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
+
+    // NOTE : because of the const id element, we cannot just assign *source = *in
+
+    source->type     	     = in->type;
+    source->mode     	     = in->mode;
+    source->mode2    	     = in->mode2;
+    source->tmpFlags 	     = in->tmpFlags;
+    source->psfMag     	     = in->psfMag;
+    source->psfMagErr 	     = in->psfMagErr;
+    source->psfFlux    	     = in->psfFlux;
+    source->psfFluxErr 	     = in->psfFluxErr;
+    source->extMag 	     = in->extMag;
+    source->apMag  	     = in->apMag;
+    source->apMagRaw  	     = in->apMagRaw;
+    source->apRadius  	     = in->apRadius;
+    source->apFlux    	     = in->apFlux;
+    source->apFluxErr 	     = in->apFluxErr;
+    source->pixWeightNotBad  = in->pixWeightNotBad;
+    source->pixWeightNotPoor = in->pixWeightNotPoor;
+    source->psfChisq         = in->psfChisq;
+    source->crNsigma         = in->crNsigma;
+    source->extNsigma        = in->extNsigma;
+    source->sky    	     = in->sky;
+    source->skyErr 	     = in->skyErr;
+
+    source->region           = in->region;
 
     return(source);
@@ -266,4 +285,16 @@
     extend |= (mySource->maskObj == NULL);
     extend |= (mySource->maskView == NULL);
+
+    // if ((fabs(x - 2020) < 5) && (fabs(y - 366) < 5)) {
+    // 	if (extend) {
+    // 	    fprintf (stderr, "extend T, %f, %f : %f, %f vs %f, %f : %f, %f\n", 
+    // 		     newRegion.x0, newRegion.y0, newRegion.x1, newRegion.y1, 
+    // 		     mySource->region.x0, mySource->region.y0, mySource->region.x1, mySource->region.y1);
+    // 	} else {
+    // 	    fprintf (stderr, "extend F, %f, %f : %f, %f vs %f, %f : %f, %f\n", 
+    // 		     newRegion.x0, newRegion.y0, newRegion.x1, newRegion.y1, 
+    // 		     mySource->region.x0, mySource->region.y0, mySource->region.x1, mySource->region.y1);
+    // 	}
+    // }
 
     if (extend) {
@@ -486,5 +517,5 @@
         // create vectors with Sx, Sy values in window
         // clip sources based on S/N
-        for (psS32 i = 0 ; i < sources->n ; i++)
+        for (psS32 i = 0; i < sources->n; i++)
         {
             pmSource *tmpSrc = (pmSource *) sources->data[i];
@@ -1175,5 +1206,5 @@
     if (!source->moments) return false;		 // can't if there are no moments
     if (!source->moments->nPixels) return false; // can't if the moments were not measured
-    if (source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE) return false; // can't if the moments failed...
+    if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) return false; // can't if the moments failed...
 
     if (source->mode & PM_SOURCE_MODE_SATSTAR) return true; // moments are best for SATSTARs
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSource.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSource.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSource.h	(revision 31606)
@@ -80,10 +80,10 @@
     pmSourceMode2 mode2;                ///< analysis flags set for object.
     pmSourceTmpF tmpFlags;              ///< internal-only flags
-    psArray *blends;                    ///< collection of sources thought to be confused with object
+
     float psfMag;                       ///< calculated from flux in modelPSF
+    float psfMagErr;                    ///< error in psfMag
     float psfFlux;                      ///< calculated from flux in modelPSF
-    float psfFluxErr;                   ///< calculated from flux in modelPSF
-    float extMag;                       ///< calculated from flux in modelEXT
-    float errMag;                       ///< error in psfMag OR extMag (depending on type)
+    float psfFluxErr;                   ///< error in psfFlux
+    float extMag;                       ///< calculated from flux in modelEXT -- NOTE this is not actually used
     float apMag;                        ///< apMag corresponding to psfMag or extMag (depending on type)
     float apMagRaw;                     ///< raw mag in given aperture
@@ -98,6 +98,9 @@
     float crNsigma;                     ///< Nsigma deviation from PSF to CR
     float extNsigma;                    ///< Nsigma deviation from PSF to EXT
-    float sky, skyErr;                  ///< The sky and its error at the center of the object
+    float sky;				///< The sky at the center of the object 
+    float skyErr;			///< The sky error at the center of the object
+
     psRegion region;                    ///< area on image covered by selected pixels
+    psArray *blends;                    ///< collection of sources thought to be confused with object
     pmSourceExtendedPars *extpars;      ///< extended source parameters
     pmSourceDiffStats *diffStats;       ///< extra parameters for difference detections
@@ -254,4 +257,5 @@
     float sigma,      ///< size of Gaussian window function (<= 0.0 -> skip window)
     float minSN,	      ///< minimum pixel significance
+    float minKronRadius,      ///< minimum pixel significance
     psImageMaskType maskVal
 );
@@ -273,4 +277,6 @@
   float xGuess, float yGuess);
 
+float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM);
+
 pmModel *pmSourceGetModel (bool *isPSF, const pmSource *source);
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 31606)
@@ -125,5 +125,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfFlux);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfFluxErr);
@@ -256,10 +256,10 @@
 
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 31606)
@@ -124,5 +124,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfFlux);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfFluxErr);
@@ -274,10 +274,10 @@
 
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 31606)
@@ -125,5 +125,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental flux (counts)",         source->psfFlux);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux",             source->psfFluxErr);
@@ -273,10 +273,10 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
@@ -720,6 +720,6 @@
       sprintf (keyword1, "RMIN_%02d", i);
       sprintf (keyword2, "RMAX_%02d", i);
-      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
-      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
     }
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 31606)
@@ -118,5 +118,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
@@ -241,10 +241,10 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 31606)
@@ -116,5 +116,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
@@ -247,10 +247,10 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 31606)
@@ -116,5 +116,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental flux (counts)",         source->psfFlux);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux",             source->psfFluxErr);
@@ -161,6 +161,8 @@
         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kinner);
         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kouter);
+
+	// Do NOT write these : not consistent with the definition of PS1_V3 in Ohana/src/libautocode/dev/cmf-ps1-v3.d
         // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_FLUX",   PS_DATA_F32, "Kron Flux (in 1.0 R1)",                      moments.KronCore);
-        // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_ERROR",  PS_DATA_F32, "Kron Error (in 1.0 R1)",                     moments.KronCoreErr);
+	// psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_ERROR",  PS_DATA_F32, "Kron Error (in 1.0 R1)",                     moments.KronCoreErr);
         psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
         psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                      source->mode2);
@@ -270,10 +272,10 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
         source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
 
         // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
         PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
@@ -292,6 +294,6 @@
 
 	// we no longer sort by S/N, only flux
-        // if (isfinite (source->errMag) && (source->errMag > 0.0)) {
-        //   source->peak->SN = 1.0 / source->errMag;
+        // if (isfinite (source->psfMagErr) && (source->psfMagErr > 0.0)) {
+        //   source->peak->SN = 1.0 / source->psfMagErr;
         // } else {
         //   source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMP.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMP.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_CMP.c	(revision 31606)
@@ -137,5 +137,5 @@
         axes = pmPSF_ModelToAxes (PAR, 20.0);
 
-        float errMag = isfinite(source->errMag) ? source->errMag : 999;
+        float psfMagErr = isfinite(source->psfMagErr) ? source->psfMagErr : 999;
 
         psLineInit (line);
@@ -143,5 +143,5 @@
         psLineAdd (line, "%6.1f ",  PAR[PM_PAR_YPOS]);
         psLineAdd (line, "%6.3f ",  PS_MIN (99.0, source->psfMag + ZERO_POINT));
-        psLineAdd (line, "%03d ",   PS_MIN (999, (int)errMag));
+        psLineAdd (line, "%03d ",   PS_MIN (999, (int)psfMagErr));
         psLineAdd (line, "%2d ",    type);
         psLineAdd (line, "%3.1f ",  lsky);
@@ -280,5 +280,5 @@
             source->psfMag = atof (array->data[2]);
             source->extMag = atof (array->data[6]);
-            source->errMag = atof (array->data[3]) / 1000.0;
+            source->psfMagErr = atof (array->data[3]) / 1000.0;
             source->apMag  = atof (array->data[7]);
             axes.major     = atof (array->data[8]);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_CAL_0.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 31606)
@@ -71,5 +71,5 @@
     psF32 xPos, yPos;
     psF32 xErr, yErr;
-    psF32 errMag, chisq;
+    psF32 psfMagErr, chisq;
 
     pmChip *chip = readout->parent->parent;
@@ -121,6 +121,6 @@
 	    chisq = model->chisq;
 
-	    // need to determine the PSF photometry error: source->errMag is the error on the 'best' model mag.
-	    errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
+	    // need to determine the PSF photometry error: source->psfMagErr is the error on the 'best' model mag.
+	    psfMagErr = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
         } else {
             xPos = source->peak->xf;
@@ -132,5 +132,5 @@
             axes.theta = NAN;
 	    chisq = NAN;
-	    errMag = NAN;
+	    psfMagErr = NAN;
         }
 
@@ -167,7 +167,7 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr);
         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "Calibrated Magnitude from PSF Fit",          calMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "Calibrated Magnitude Error",                 errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "Calibrated Magnitude Error",                 psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
         psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
@@ -284,7 +284,7 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
 	PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-	dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+	dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_0.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 31606)
@@ -113,5 +113,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             PS_MIN (99.0, source->psfMag));
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        PS_MIN (99.0, source->errMag));
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        PS_MIN (99.0, source->psfMagErr));
         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           PS_MIN (99.0, peakMag));
         psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
@@ -212,5 +212,5 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 31606)
@@ -70,5 +70,5 @@
     psF32 xPos, yPos;
     psF32 xErr, yErr;
-    psF32 errMag, chisq;
+    psF32 psfMagErr, chisq;
 
     // let's write these out in S/N order
@@ -103,6 +103,6 @@
 	    chisq = model->chisq;
 
-	    // need to determine the PSF photometry error: source->errMag is the error on the 'best' model mag.
-	    errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
+	    // need to determine the PSF photometry error: source->psfMagErr is the error on the 'best' model mag.
+	    psfMagErr = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
         } else {
             xPos = source->peak->xf;
@@ -114,5 +114,5 @@
             axes.theta = NAN;
 	    chisq = NAN;
-	    errMag = NAN;
+	    psfMagErr = NAN;
         }
 
@@ -128,5 +128,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        psfMagErr);
         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
         psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
@@ -253,7 +253,7 @@
         // XXX use these to determine PAR[PM_PAR_I0]?
         source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
-        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->psfMagErr    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
 	PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
-	dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+	dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->psfMagErr : NAN;
 
         pmPSF_AxesToModel (PAR, axes);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_RAW.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_RAW.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_RAW.c	(revision 31606)
@@ -110,5 +110,5 @@
         fprintf (f, "%7.1f %7.1f  %7.1f %8.4f  %7.4f %7.4f  ",
                  PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], source->sky,
-                 source->psfMag, source->errMag, dPos);
+                 source->psfMag, source->psfMagErr, dPos);
 
         for (j = 4; j < model->params->n; j++) {
@@ -174,5 +174,5 @@
         fprintf (f, "%7.1f %7.1f  %7.1f %8.4f  %7.4f %7.4f  ",
                  PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], source->sky,
-                 source->extMag, source->errMag, dPos);
+                 source->extMag, source->psfMagErr, dPos);
 
         for (j = 4; j < model->params->n; j++) {
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SMPDATA.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 31606)
@@ -106,5 +106,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_PIX",   PS_DATA_F32, "", yPos);
         psMetadataAdd (row, PS_LIST_TAIL, "MAG_RAW", PS_DATA_F32, "", PS_MIN (99.0, source->psfMag + ZERO_POINT));
-        psMetadataAdd (row, PS_LIST_TAIL, "MAG_ERR", PS_DATA_F32, "", PS_MIN (999, 1000*source->errMag));
+        psMetadataAdd (row, PS_LIST_TAIL, "MAG_ERR", PS_DATA_F32, "", PS_MIN (999, 1000*source->psfMagErr));
         psMetadataAdd (row, PS_LIST_TAIL, "MAG_GAL", PS_DATA_F32, "", PS_MIN (99.0, source->extMag + ZERO_POINT));
         psMetadataAdd (row, PS_LIST_TAIL, "MAG_AP",  PS_DATA_F32, "", PS_MIN (99.0, source->apMag + ZERO_POINT));
@@ -194,5 +194,5 @@
         source->psfMag = psMetadataLookupF32 (&status, row, "MAG_RAW") - ZERO_POINT;
         source->extMag = psMetadataLookupF32 (&status, row, "MAG_GAL") - ZERO_POINT;
-        source->errMag = psMetadataLookupF32 (&status, row, "MAG_ERR") * 0.001;
+        source->psfMagErr = psMetadataLookupF32 (&status, row, "MAG_ERR") * 0.001;
         source->apMag  = psMetadataLookupF32 (&status, row, "MAG_AP")  - ZERO_POINT;
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SX.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SX.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceIO_SX.c	(revision 31606)
@@ -88,5 +88,5 @@
         psLineAdd (line, "%11.3f", PAR[PM_PAR_YPOS]);
         psLineAdd (line, "%9.4f",  source->psfMag);
-        psLineAdd (line, "%9.4f",  source->errMag);
+        psLineAdd (line, "%9.4f",  source->psfMagErr);
         psLineAdd (line, "%13.4f", source->sky);
         psLineAdd (line, "%9.2f",  axes.major);
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceMasks.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceMasks.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceMasks.h	(revision 31606)
@@ -14,5 +14,5 @@
     PM_SOURCE_MODE_PSFSTAR          = 0x00000040, ///< Source used to define PSF model
     PM_SOURCE_MODE_SATSTAR          = 0x00000080, ///< Source model peak is above saturation
-    PM_SOURCE_MODE_BLEND            = 0x00000100, ///< Source is a blend with other sourcers
+    PM_SOURCE_MODE_BLEND            = 0x00000100, ///< Source is a blend with other sources
     PM_SOURCE_MODE_EXTERNAL         = 0x00000200, ///< Source based on supplied input position
     PM_SOURCE_MODE_BADPSF           = 0x00000400, ///< Failed to get good estimate of object's PSF
@@ -51,4 +51,6 @@
     PM_SOURCE_MODE2_ON_BURNTOOL      = 0x00000020, ///< > 25% of (PSF-weighted) pixels land on burntool
     PM_SOURCE_MODE2_ON_CONVPOOR      = 0x00000040, ///< > 25% of (PSF-weighted) pixels land on convpoor
+
+    PM_SOURCE_MODE2_PASS1_SRC        = 0x00000080, ///< source detected in first pass analysis
 } pmSourceMode2;
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceMatch.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceMatch.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceMatch.c	(revision 31606)
@@ -88,5 +88,5 @@
         pmSource *source = sources->data[i]; // Source of interest
         if (!source || (source->mode & SOURCE_MASK) || !isfinite(source->psfMag) ||
-            !isfinite(source->errMag) || source->psfMag > SOURCE_FAINTEST) {
+            !isfinite(source->psfMagErr) || source->psfMag > SOURCE_FAINTEST) {
             continue;
         }
@@ -102,5 +102,5 @@
         (*y)->data.F32[num] = ySrc;
         (*mag)->data.F32[num] = source->psfMag;
-        (*magErr)->data.F32[num] = source->errMag;
+        (*magErr)->data.F32[num] = source->psfMagErr;
         (*indices)->data.S32[num] = i;
         num++;
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceMoments.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceMoments.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceMoments.c	(revision 31606)
@@ -66,5 +66,5 @@
 // if mode & EXTERNAL or mode2 & MATCHED, do not re-calculate the centroid (use peak as centroid)
 
-bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal)
+bool pmSourceMoments(pmSource *source, float radius, float sigma, float minSN, float minKronRadius, psImageMaskType maskVal)
 {
     PS_ASSERT_PTR_NON_NULL(source, false);
@@ -74,5 +74,5 @@
 
     // this function assumes the sky has been well-subtracted for the image
-    psF32 sky = 0.0;
+    float sky = 0.0;
 
     if (source->moments == NULL) {
@@ -80,11 +80,11 @@
     }
 
-    psF32 Sum = 0.0;
-    psF32 Var = 0.0;
-    psF32 SumCore = 0.0;
-    psF32 VarCore = 0.0;
-    psF32 R2 = PS_SQR(radius);
-    psF32 minSN2 = PS_SQR(minSN);
-    psF32 rsigma2 = 0.5 / PS_SQR(sigma);
+    float Sum = 0.0;
+    float Var = 0.0;
+    float SumCore = 0.0;
+    float VarCore = 0.0;
+    float R2 = PS_SQR(radius);
+    float minSN2 = PS_SQR(minSN);
+    float rsigma2 = 0.5 / PS_SQR(sigma);
 
     // a note about coordinates: coordinates of objects throughout psphot refer to the primary
@@ -109,35 +109,48 @@
     // Xn  = SUM (x - xc)^n * (z - sky)
 
-    psF32 RF = 0.0;
-    psF32 RH = 0.0;
-    psF32 RS = 0.0;
-    psF32 XX = 0.0;
-    psF32 XY = 0.0;
-    psF32 YY = 0.0;
-    psF32 XXX = 0.0;
-    psF32 XXY = 0.0;
-    psF32 XYY = 0.0;
-    psF32 YYY = 0.0;
-    psF32 XXXX = 0.0;
-    psF32 XXXY = 0.0;
-    psF32 XXYY = 0.0;
-    psF32 XYYY = 0.0;
-    psF32 YYYY = 0.0;
+    float RFW = 0.0;
+    float RHW = 0.0;
+
+    float RF = 0.0;
+    float RH = 0.0;
+    float RS = 0.0;
+    float XX = 0.0;
+    float XY = 0.0;
+    float YY = 0.0;
+    float XXX = 0.0;
+    float XXY = 0.0;
+    float XYY = 0.0;
+    float YYY = 0.0;
+    float XXXX = 0.0;
+    float XXXY = 0.0;
+    float XXYY = 0.0;
+    float XYYY = 0.0;
+    float YYYY = 0.0;
 
     Sum = 0.0;  // the second pass may include slightly different pixels, re-determine Sum
+
+    // float dX = source->moments->Mx - source->peak->xf;
+    // float dY = source->moments->My - source->peak->yf;
+    // float dR = hypot(dX, dY);
+    // float Xo = (dR < 2.0) ? source->moments->Mx : source->peak->xf;
+    // float Yo = (dR < 2.0) ? source->moments->My : source->peak->yf;
+    float Xo = source->moments->Mx;
+    float Yo = source->moments->My;
 
     // center of mass in subimage.  Note: the calculation below uses pixel index, so we correct
     // xCM, yCM from pixel coords to pixel index here.
-    psF32 xCM = source->moments->Mx - 0.5 - source->pixels->col0; // coord of peak in subimage
-    psF32 yCM = source->moments->My - 0.5 - source->pixels->row0; // coord of peak in subimage
+    float xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage
+    float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage
 
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
 
-	psF32 yDiff = row - yCM;
+	float yDiff = row - yCM;
 	if (fabs(yDiff) > radius) continue;
 
-	psF32 *vPix = source->pixels->data.F32[row];
-	psF32 *vWgt = source->variance->data.F32[row];
+	float *vPix = source->pixels->data.F32[row];
+	float *vWgt = source->variance->data.F32[row];
+
 	psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+	// psImageMaskType  *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
 
 	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
@@ -151,14 +164,14 @@
 	    if (isnan(*vPix)) continue;
 
-	    psF32 xDiff = col - xCM;
+	    float xDiff = col - xCM;
 	    if (fabs(xDiff) > radius) continue;
 
 	    // radius is just a function of (xDiff, yDiff)
-	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
 	    if (r2 > R2) continue;
 
-	    psF32 fDiff = *vPix - sky;
-	    psF32 pDiff = fDiff;
-	    psF32 wDiff = *vWgt;
+	    float fDiff = *vPix - sky;
+	    float pDiff = fDiff;
+	    float wDiff = *vWgt;
 
 	    // skip pixels below specified significance level.  this is allowed, but should be
@@ -171,7 +184,7 @@
 	    // weighting over weights the sky for faint sources
 	    if (sigma > 0.0) {
-		psF32 z = r2 * rsigma2;
+		float z = r2 * rsigma2;
 		assert (z >= 0.0);
-		psF32 weight  = exp(-z);
+		float weight  = exp(-z);
 
 		wDiff *= weight;
@@ -182,30 +195,36 @@
 
 	    // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)
-	    psF32 r = sqrt(r2);
-	    psF32 rf = r * fDiff;
-	    psF32 rh = sqrt(r) * fDiff;
-	    psF32 rs = fDiff;
-
-	    psF32 x = xDiff * pDiff;
-	    psF32 y = yDiff * pDiff;
-
-	    psF32 xx = xDiff * x;
-	    psF32 xy = xDiff * y;
-	    psF32 yy = yDiff * y;
-
-	    psF32 xxx = xDiff * xx / r;
-	    psF32 xxy = xDiff * xy / r;
-	    psF32 xyy = xDiff * yy / r;
-	    psF32 yyy = yDiff * yy / r;
-
-	    psF32 xxxx = xDiff * xxx / r2;
-	    psF32 xxxy = xDiff * xxy / r2;
-	    psF32 xxyy = xDiff * xyy / r2;
-	    psF32 xyyy = xDiff * yyy / r2;
-	    psF32 yyyy = yDiff * yyy / r2;
+	    float r = sqrt(r2);
+	    float rf = r * fDiff;
+	    float rh = sqrt(r) * fDiff;
+	    float rs = fDiff;
+
+	    float rfw = r * pDiff;
+	    float rhw = sqrt(r) * pDiff;
+
+	    float x = xDiff * pDiff;
+	    float y = yDiff * pDiff;
+
+	    float xx = xDiff * x;
+	    float xy = xDiff * y;
+	    float yy = yDiff * y;
+
+	    float xxx = xDiff * xx / r;
+	    float xxy = xDiff * xy / r;
+	    float xyy = xDiff * yy / r;
+	    float yyy = yDiff * yy / r;
+
+	    float xxxx = xDiff * xxx / r2;
+	    float xxxy = xDiff * xxy / r2;
+	    float xxyy = xDiff * xyy / r2;
+	    float xyyy = xDiff * yyy / r2;
+	    float yyyy = yDiff * yyy / r2;
 
 	    RF  += rf;
 	    RH  += rh;
 	    RS  += rs;
+
+	    RFW  += rfw;
+	    RHW  += rhw;
 
 	    XX  += xx;
@@ -244,8 +263,12 @@
     source->moments->Myyyy = YYYY/Sum;
 
-    // Calculate the Kron magnitude (make this block optional?)
-    float radKinner = 1.0*source->moments->Mrf;
-    float radKron   = 2.5*source->moments->Mrf;
-    float radKouter = 4.0*source->moments->Mrf;
+    // if Mrf (first radial moment) is very small, we are getting into low-significance
+    // territory.  saturate at minKronRadius.  conversely, if Mrf is > radius, we are clearly
+    // making an error.  saturate at radius.
+    float kronRefRadius = MIN(radius, MAX(minKronRadius, source->moments->Mrf));
+
+    float radKinner = 1.0*kronRefRadius;
+    float radKron   = 2.5*kronRefRadius;
+    float radKouter = 4.0*kronRefRadius;
 
     int nKronPix = 0;
@@ -259,10 +282,12 @@
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
 
-	psF32 yDiff = row - yCM;
+	float yDiff = row - yCM;
 	if (fabs(yDiff) > radKouter) continue;
 
-	psF32 *vPix = source->pixels->data.F32[row];
-	psF32 *vWgt = source->variance->data.F32[row];
+	float *vPix = source->pixels->data.F32[row];
+	float *vWgt = source->variance->data.F32[row];
+
 	psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+	// psImageMaskType  *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
 
 	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
@@ -276,12 +301,12 @@
 	    if (isnan(*vPix)) continue;
 
-	    psF32 xDiff = col - xCM;
+	    float xDiff = col - xCM;
 	    if (fabs(xDiff) > radKouter) continue;
 
 	    // radKron is just a function of (xDiff, yDiff)
-	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
-
-	    psF32 pDiff = *vPix - sky;
-	    psF32 wDiff = *vWgt;
+	    float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+
+	    float pDiff = *vPix - sky;
+	    float wDiff = *vWgt;
 
 	    // skip pixels below specified significance level.  this is allowed, but should be
@@ -290,5 +315,5 @@
 	    if (PS_SQR(pDiff) < minSN2*wDiff) continue;
 
-	    psF32 r  = sqrt(r2);
+	    float r  = sqrt(r2);
 	    if (r < radKron) {
 		Sum += pDiff;
@@ -335,5 +360,5 @@
 }
 
-bool pmSourceMomentsGetCentroid(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal, float xGuess, float yGuess) { 
+bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) { 
 
     // First Pass: calculate the first moments (these are subtracted from the coordinates below)
@@ -342,15 +367,15 @@
     // .. etc
 
-    psF32 sky = 0.0;
-
-    psF32 peakPixel = -PS_MAX_F32;
+    float sky = 0.0;
+
+    float peakPixel = -PS_MAX_F32;
     psS32 numPixels = 0;
-    psF32 Sum = 0.0;
-    psF32 Var = 0.0;
-    psF32 X1 = 0.0;
-    psF32 Y1 = 0.0;
-    psF32 R2 = PS_SQR(radius);
-    psF32 minSN2 = PS_SQR(minSN);
-    psF32 rsigma2 = 0.5 / PS_SQR(sigma);
+    float Sum = 0.0;
+    float Var = 0.0;
+    float X1 = 0.0;
+    float Y1 = 0.0;
+    float R2 = PS_SQR(radius);
+    float minSN2 = PS_SQR(minSN);
+    float rsigma2 = 0.5 / PS_SQR(sigma);
 
     float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage
@@ -358,5 +383,5 @@
 
     // we are guaranteed to have a valid pixel and variance at this location (right? right?)
-    // psF32 weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
+    // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
     // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
     // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
@@ -370,10 +395,12 @@
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
 
-	psF32 yDiff = row + 0.5 - yPeak;
+	float yDiff = row + 0.5 - yPeak;
 	if (fabs(yDiff) > radius) continue;
 
-	psF32 *vPix = source->pixels->data.F32[row];
-	psF32 *vWgt = source->variance->data.F32[row];
+	float *vPix = source->pixels->data.F32[row];
+	float *vWgt = source->variance->data.F32[row];
+
 	psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+	// psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];
 
 	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
@@ -387,13 +414,13 @@
 	    if (isnan(*vPix)) continue;
 
-	    psF32 xDiff = col + 0.5 - xPeak;
+	    float xDiff = col + 0.5 - xPeak;
 	    if (fabs(xDiff) > radius) continue;
 
 	    // radius is just a function of (xDiff, yDiff)
-	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    float r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
 	    if (r2 > R2) continue;
 
-	    psF32 pDiff = *vPix - sky;
-	    psF32 wDiff = *vWgt;
+	    float pDiff = *vPix - sky;
+	    float wDiff = *vWgt;
 
 	    // skip pixels below specified significance level.  for a PSFs, this
@@ -408,7 +435,7 @@
 	    // weighting over weights the sky for faint sources
 	    if (sigma > 0.0) {
-		psF32 z  = r2*rsigma2;
+		float z  = r2*rsigma2;
 		assert (z >= 0.0);
-		psF32 weight  = exp(-z);
+		float weight  = exp(-z);
 
 		wDiff *= weight;
@@ -419,6 +446,6 @@
 	    Sum += pDiff;
 
-	    psF32 xWght = xDiff * pDiff;
-	    psF32 yWght = yDiff * pDiff;
+	    float xWght = xDiff * pDiff;
+	    float yWght = yDiff * pDiff;
 
 	    X1  += xWght;
@@ -477,2 +504,42 @@
     return true;
 }
+
+float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM) {
+
+    psVector *radii = psVectorAllocEmpty(100, PS_TYPE_F32);
+
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *src = sources->data[i]; // Source of interest
+	if (!src || !src->moments) {
+	    continue;
+	}
+
+	if (src->mode & PM_SOURCE_MODE_BLEND) {
+	    continue;
+	}
+
+	if (!src->moments->nPixels) continue;
+
+	if (src->moments->SN < PSF_SN_LIM) continue;
+
+	// XXX put in Mxx,Myy cut based on clump location
+
+	psVectorAppend(radii, src->moments->Mrf);
+    }
+
+    // find the peak in this image
+    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
+
+    if (!psVectorStats (stats, radii, NULL, NULL, 0)) {
+	psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
+	psFree(stats);
+	return NAN;
+    }
+
+    float minRadius = stats->sampleMedian;
+
+    psFree(radii);
+    psFree(stats);
+    return minRadius;
+}
+
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceOutputs.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceOutputs.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceOutputs.c	(revision 31606)
@@ -98,12 +98,13 @@
 	outputs->xPos = PAR[PM_PAR_XPOS];
 	outputs->yPos = PAR[PM_PAR_YPOS];
-	if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
+	if ((source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) && !(source->mode & PM_SOURCE_MODE_EXTMODEL)) {
+	    // we only do non-linear PSF fits for non-extended objects
 	    outputs->xErr = dPAR[PM_PAR_XPOS];
 	    outputs->yErr = dPAR[PM_PAR_YPOS];
 	} else {
-	    outputs->xErr = fwhmMajor * source->errMag / 2.35;
-	    outputs->yErr = fwhmMinor * source->errMag / 2.35;
+	    outputs->xErr = fwhmMajor * source->psfMagErr / 2.35;
+	    outputs->yErr = fwhmMinor * source->psfMagErr / 2.35;
 	}
-	if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
+	if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXY]) && isfinite(PAR[PM_PAR_SYY])) {
 	    axes = pmPSF_ModelToAxes (PAR, 20.0);
 	    outputs->psfMajor = axes.major;
@@ -125,6 +126,6 @@
 	    outputs->xPos = source->moments->Mx;
 	    outputs->yPos = source->moments->My;
-	    outputs->xErr = fwhmMajor * source->errMag / 2.35;
-	    outputs->yErr = fwhmMinor * source->errMag / 2.35;
+	    outputs->xErr = fwhmMajor * source->psfMagErr / 2.35;
+	    outputs->yErr = fwhmMinor * source->psfMagErr / 2.35;
 	} else {
 	    outputs->xPos = source->peak->xf;
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.c	(revision 31606)
@@ -82,11 +82,8 @@
    - apMag  : only if S/N > AP_MIN_SN
    : is optionally corrected for curve-of-growth if:
-   - the source is a STAR (PSF)
    - the option is selected (mode & PM_SOURCE_PHOT_GROWTH)
    - psfMag : all sources with non-NULL modelPSF
    : is optionally corrected for aperture residual if:
-   - the source is a STAR (PSF)
    - the option is selected (mode & PM_SOURCE_PHOT_APCORR)
-
    - extMag : all sources with non-NULL modelEXT
 **/
@@ -100,13 +97,10 @@
 
     int status = false;
-    bool isPSF;
     float x, y;
-    float rflux;
     float SN;
-    pmModel *model;
 
     source->psfMag    = NAN;
     source->extMag    = NAN;
-    source->errMag    = NAN;
+    source->psfMagErr = NAN;
     source->apMag     = NAN;
     source->apMagRaw  = NAN;
@@ -114,38 +108,42 @@
     source->apFluxErr = NAN;
 
-    // we must have a valid model
-    // XXX allow aperture magnitudes for sources without a model
-    model = pmSourceGetModel (&isPSF, source);
-    if (model == NULL) {
-        psTrace ("psModules.objects", 3, "fail mag : no valid model");
+    // XXXXXX review:
+    // Select the 'best' model -- this is used for PSF_QF,_PERFECT & ???. isPSF is true if this
+    // object is a PSF (not extended).  We must have a valid model.  XXX NOTE: allow aperture
+    // magnitudes for sources without a model
+
+    // select the psf model
+    pmModel *modelPSF = source->modelPSF;
+    if (modelPSF == NULL) {
+        psTrace ("psModules.objects", 3, "fail mag : no valid PSF model");
         return false;
     }
 
-    // XXX handle negative flux, low-significance
-    if (model->dparams->data.F32[PM_PAR_I0] > 0) {
-        SN = fabs(model->params->data.F32[PM_PAR_I0] / model->dparams->data.F32[PM_PAR_I0]);
-        source->errMag = 1.0 / SN;
+    // get the error on the PSF model magnitude
+    if (modelPSF->dparams->data.F32[PM_PAR_I0] > 0) {
+        SN = fabs(modelPSF->params->data.F32[PM_PAR_I0] / modelPSF->dparams->data.F32[PM_PAR_I0]);
+        source->psfMagErr = 1.0 / SN;
     } else {
         SN = NAN;
-        source->errMag = NAN;
-    }
-    x = model->params->data.F32[PM_PAR_XPOS];
-    y = model->params->data.F32[PM_PAR_YPOS];
+        source->psfMagErr = NAN;
+    }
+    // the source position is used to recenter the aperture for ap photometry
+    x = modelPSF->params->data.F32[PM_PAR_XPOS];
+    y = modelPSF->params->data.F32[PM_PAR_YPOS];
 
     // measure PSF model photometry
-    // XXX TEST: do not use flux scale
-    // XXX NOTE: turn this back on?
-    if (0 && psf->FluxScale) {
-        // the source peak pixel is guaranteed to be on the image, and only minimally different from the source center
-        double fluxScale = pmTrend2DEval (psf->FluxScale, (float)source->peak->x, (float)source->peak->y);
-        psAssert (isfinite(fluxScale), "how can the flux scale be invalid? source at %d, %d\n", source->peak->x, source->peak->y);
-        psAssert (fluxScale > 0.0, "how can the flux scale be negative? source at %d, %d\n", source->peak->x, source->peak->y);
-        source->psfFlux = fluxScale * source->modelPSF->params->data.F32[PM_PAR_I0];
-        source->psfFluxErr = fluxScale * source->modelPSF->dparams->data.F32[PM_PAR_I0];
-        source->psfMag = -2.5*log10(source->psfFlux);
-    } else {
-        status = pmSourcePhotometryModel (&source->psfMag, &source->psfFlux, source->modelPSF);
-        source->psfFluxErr = source->psfFlux * (source->modelPSF->dparams->data.F32[PM_PAR_I0] / source->modelPSF->params->data.F32[PM_PAR_I0]);
-    }
+    status = pmSourcePhotometryModel (&source->psfMag, &source->psfFlux, modelPSF);
+    source->psfFluxErr = source->psfFlux * source->psfMagErr;
+
+# if (0)
+    // XXX NOTE: old code to use the flux scale.  test & turn this back on?  if so, need to save with psf model
+    // the source peak pixel is guaranteed to be on the image, and only minimally different from the source center
+    double fluxScale = pmTrend2DEval (psf->FluxScale, (float)source->peak->x, (float)source->peak->y);
+    psAssert (isfinite(fluxScale), "how can the flux scale be invalid? source at %d, %d\n", source->peak->x, source->peak->y);
+    psAssert (fluxScale > 0.0, "how can the flux scale be negative? source at %d, %d\n", source->peak->x, source->peak->y);
+    source->psfFlux = fluxScale * modelPSF->params->data.F32[PM_PAR_I0];
+    source->psfFluxErr = fluxScale * modelPSF->dparams->data.F32[PM_PAR_I0];
+    source->psfMag = -2.5*log10(source->psfFlux);
+# endif
 
     if (mode == PM_SOURCE_PHOT_PSFONLY) {
@@ -153,4 +151,5 @@
     }
 
+    // get the EXT model photometry (all EXT models)
     // if we have a collection of model fits, check if one of them is a pointer to modelEXT
     if (source->modelFits) {
@@ -173,15 +172,16 @@
     }
 
-    // for PSFs, correct both apMag and psfMag to same system, consistent with infinite flux star in aperture RADIUS
-    // XXX add a flag for "ap_mag is corrected?"
-    if ((mode & PM_SOURCE_PHOT_APCORR) && isPSF && psf && psf->ApTrend) {
+    // Correct psfMag to match aperture magnitude system (NOTE : Growth curve is already applied to ApTrend)
+    if ((mode & PM_SOURCE_PHOT_APCORR) && psf && psf->ApTrend) {
         // the source peak pixel is guaranteed to be on the image, and only minimally different from the source center
         double apTrend = pmTrend2DEval (psf->ApTrend, (float)source->peak->x, (float)source->peak->y);
         source->psfMag += apTrend;
-    }
-
-    // measure the contribution of included pixels
+	source->psfFlux *= pow(10.0, -0.4*apTrend);
+	source->psfFluxErr *= pow(10.0, -0.4*apTrend);
+    }
+
+    // measure the contribution of included pixels to the PSF model fit
     if (mode & PM_SOURCE_PHOT_WEIGHT) {
-        pmSourcePixelWeight (source, model, source->maskObj, maskVal, radius);
+        pmSourcePixelWeight (source, modelPSF, source->maskObj, maskVal, radius);
     }
 
@@ -217,6 +217,7 @@
         y += dy;
 
-        if (!psImageShiftMask(&flux, &mask, source->pixels, source->maskObj, maskVal, dx, dy,
-                              NAN, 0xff, PS_INTERPOLATE_BIQUADRATIC)) {
+        // if (!psImageShiftMask(&flux, &mask, source->pixels, source->maskObj, maskVal, dx, dy, NAN, 0xff, PS_INTERPOLATE_LANCZOS2)) {
+	// if (!psImageShiftMask(&flux, &mask, source->pixels, source->maskObj, maskVal, dx, dy, NAN, 0xff, PS_INTERPOLATE_BIQUADRATIC)) {
+	if (!psImageShiftMask(&flux, &mask, source->pixels, source->maskObj, maskVal, dx, dy, NAN, 0xff, PS_INTERPOLATE_BILINEAR)) {
             // Not much we can do about it
             psErrorClear();
@@ -232,5 +233,5 @@
 
     // measure object aperture photometry
-    status = pmSourcePhotometryAperSource (source, model, flux, variance, mask, maskVal);
+    status = pmSourcePhotometryAperSource (source, modelPSF, flux, variance, mask, maskVal);
     if (!status) {
         psTrace ("psModules.objects", 3, "fail mag : bad Ap Mag");
@@ -241,16 +242,10 @@
     // detection limits (esp near bright neighbors)
     source->apMag = source->apMagRaw;
-    if (isfinite (source->apMag) && isPSF && psf) {
+    if (isfinite (source->apMag) && psf) {
         if (psf->growth && (mode & PM_SOURCE_PHOT_GROWTH)) {
-            source->apMag = source->apMagRaw + pmGrowthCurveCorrect (psf->growth, source->apRadius);
-	    // XXX correct the apFlux?
-        }
-        if (mode & PM_SOURCE_PHOT_APCORR) {
-            // XXX this should be removed -- we no longer fit for the 'sky bias'
-	    // XXX is this happening???
-            rflux   = pow (10.0, 0.4*source->psfMag);
-	    psAssert (psf->skyBias == 0.0, "sky bias not 0");
-	    psAssert (psf->skySat == 0.0, "sky sat not 0");
-            source->apMag -= PS_SQR(source->apRadius)*rflux * psf->skyBias + psf->skySat / rflux;
+	    float apOffset = pmGrowthCurveCorrect (psf->growth, source->apRadius);
+            source->apMag = source->apMagRaw + apOffset;
+	    source->apFlux *= pow(10.0, -0.4*apOffset);
+	    source->apFluxErr *= pow(10.0, -0.4*apOffset);
         }
     }
@@ -309,11 +304,14 @@
 
     bool status;
-    status = pmSourcePhotometryAper(&source->apMagRaw, &source->apFlux, &source->apFluxErr, model, image, variance, mask, maskVal);
-
+    int nPix = 0;
+    status = pmSourcePhotometryAper(&nPix, &source->apMagRaw, &source->apFlux, &source->apFluxErr, model, image, variance, mask, maskVal);
+    if (status) {
+	source->mode |= PM_SOURCE_MODE_AP_MAGS;
+    }
     return status;
 }
 
 // return source aperture magnitude
-bool pmSourcePhotometryAper (float *apMag, float *apFluxOut, float *apFluxErr, pmModel *model, psImage *image, psImage *variance, psImage *mask, psImageMaskType maskVal)
+bool pmSourcePhotometryAper (int *nPixOut, float *apMag, float *apFluxOut, float *apFluxErr, pmModel *model, psImage *image, psImage *variance, psImage *mask, psImageMaskType maskVal)
 {
     PS_ASSERT_PTR_NON_NULL(apMag, false);
@@ -328,4 +326,5 @@
     float apFlux = 0;
     float apFluxVar = 0;
+    int nPix = 0;
 
     if (DO_SKY) {
@@ -345,8 +344,11 @@
             apFlux += imData[iy][ix] - sky;
             apFluxVar += varData[iy][ix];
-        }
-    }
+	    nPix ++;
+        }
+    }
+    
     if (apFluxOut) *apFluxOut = apFlux;
     if (apFluxErr) *apFluxErr = sqrt(fabs(apFluxVar));
+    if (nPixOut) *nPixOut = nPix;
 
     if (apFlux <= 0) {
@@ -412,4 +414,6 @@
     psImageMaskType maskBad = maskVal;
     maskBad &= ~maskSuspect;
+
+    psImageMaskType maskPoor = maskVal | maskSuspect;
 
     // measure modelSum and validSum.  this function is applied to a sources' subimage.  the
@@ -446,5 +450,5 @@
 
 	    // count pixels which are masked with an mask bit (bad or poor)
-            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskVal)) {
+            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskPoor)) {
 		notPoorSum += value;
 	    }
@@ -487,5 +491,5 @@
 
     if (isfinite(source->pixWeightNotBad) && isfinite(source->pixWeightNotPoor)) {
-	psAssert (source->pixWeightNotBad <= source->pixWeightNotPoor, "error: all bad pixels should also be poor");
+	psAssert (source->pixWeightNotPoor <= source->pixWeightNotBad, "error: all bad pixels should also be poor");
     }
 
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourcePhotometry.h	(revision 31606)
@@ -45,4 +45,5 @@
 
 bool pmSourcePhotometryAper(
+    int *nPixOut,
     float *apMag,
     float *apFluxOut,
Index: /branches/czw_branch/20110406/psModules/src/objects/pmSourceUtils.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/objects/pmSourceUtils.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/objects/pmSourceUtils.h	(revision 31606)
@@ -38,3 +38,3 @@
 
 /// @}
-# endif /* PM_MODEL_CLASS_H */
+# endif /* PM_SOURCE_UTILS_H */
Index: /branches/czw_branch/20110406/psModules/src/psmodules.h
===================================================================
--- /branches/czw_branch/20110406/psModules/src/psmodules.h	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/src/psmodules.h	(revision 31606)
@@ -148,4 +148,5 @@
 #include <pmModelUtils.h>
 #include <pmSourcePhotometry.h>
+#include <pmGrowthCurveGenerate.h>
 #include <pmSourceVisual.h>
 #include <pmSourceMatch.h>
Index: /branches/czw_branch/20110406/psModules/test/objects/tap_pmSource.c
===================================================================
--- /branches/czw_branch/20110406/psModules/test/objects/tap_pmSource.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/test/objects/tap_pmSource.c	(revision 31606)
@@ -91,5 +91,5 @@
         ok(isnan(src->psfMag), "pmSourceAlloc() pmSource->psfMag correctly");
         ok(isnan(src->extMag), "pmSourceAlloc() pmSource->extMag correctly");
-        ok(isnan(src->errMag), "pmSourceAlloc() pmSource->errMag correctly");
+        ok(isnan(src->psfMagErr), "pmSourceAlloc() pmSource->psfMagErr correctly");
         ok(isnan(src->apMag), "pmSourceAlloc() pmSource->apMag correctly");
         ok(isnan(src->sky), "pmSourceAlloc() pmSource->sky correctly");
Index: /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_0.c
===================================================================
--- /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_0.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_0.c	(revision 31606)
@@ -167,5 +167,5 @@
             model->dparams->data.F32[PM_PAR_YPOS] = TEST_BASE_Y_ERR + (float) i;
             src->psfMag = TEST_BASE_PSF_MAG + (float) i;
-            src->errMag = TEST_BASE_ERR_MAG + (float) i;
+            src->psfMagErr = TEST_BASE_ERR_MAG + (float) i;
             src->peak->flux = TEST_BASE_PEAK_FLUX + (float) i;
             src->sky = TEST_BASE_SKY + (float) i;
@@ -215,6 +215,6 @@
              ok(src->psfMag == (TEST_BASE_PSF_MAG + (float) i), "pmSourcesRead_PS1_DEV_0() set src->psfMag correctly (is %.2f, should be %.2f)",
                 src->psfMag, (TEST_BASE_PSF_MAG + (float) i));
-             ok(src->errMag == (TEST_BASE_ERR_MAG + (float) i), "pmSourcesRead_PS1_DEV_0() set src->errMag correctly (is %.2f, should be %.2f)",
-                src->errMag, (TEST_BASE_ERR_MAG + (float) i));
+             ok(src->psfMagErr == (TEST_BASE_ERR_MAG + (float) i), "pmSourcesRead_PS1_DEV_0() set src->psfMagErr correctly (is %.2f, should be %.2f)",
+                src->psfMagErr, (TEST_BASE_ERR_MAG + (float) i));
 
              // XXX: Source code always sets src->modelPSF.  Is that right?
Index: /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_1.c
===================================================================
--- /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_1.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_PS1_DEV_1.c	(revision 31606)
@@ -196,5 +196,5 @@
             model->dparams->data.F32[PM_PAR_YPOS] = TEST_BASE_Y_ERR + (float) i;
             src->psfMag = TEST_BASE_PSF_MAG + (float) i;
-            src->errMag = TEST_BASE_ERR_MAG + (float) i;
+            src->psfMagErr = TEST_BASE_ERR_MAG + (float) i;
             src->peak->flux = TEST_BASE_PEAK_FLUX + (float) i;
             src->sky = TEST_BASE_SKY + (float) i;
@@ -203,5 +203,5 @@
             sources->data[i] = (psPtr *) src;
             src->psfMag = TEST_BASE_PSF_MAG + (float) i;
-            src->errMag = TEST_BASE_ERR_MAG + (float) i;
+            src->psfMagErr = TEST_BASE_ERR_MAG + (float) i;
             src->sky = TEST_BASE_SKY + (float) i;
             src->skyErr = TEST_BASE_SKY_ERR + (float) i;
@@ -280,6 +280,6 @@
              ok(src->psfMag == (TEST_BASE_PSF_MAG + (float) i), "pmSourcesRead_PS1_DEV_1() set src->psfMag correctly (is %.2f, should be %.2f)",
                 src->psfMag, (TEST_BASE_PSF_MAG + (float) i));
-             ok(src->errMag == (TEST_BASE_ERR_MAG + (float) i), "pmSourcesRead_PS1_DEV_1() set src->errMag correctly (is %.2f, should be %.2f)",
-                src->errMag, (TEST_BASE_ERR_MAG + (float) i));
+             ok(src->psfMagErr == (TEST_BASE_ERR_MAG + (float) i), "pmSourcesRead_PS1_DEV_1() set src->psfMagErr correctly (is %.2f, should be %.2f)",
+                src->psfMagErr, (TEST_BASE_ERR_MAG + (float) i));
 
              // XXX: Source code always sets src->modelPSF.  Is that right?
Index: /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_SMPDATA.c
===================================================================
--- /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_SMPDATA.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourceIO_SMPDATA.c	(revision 31606)
@@ -167,5 +167,5 @@
             model->dparams->data.F32[PM_PAR_YPOS] = TEST_BASE_Y_ERR + (float) i;
             src->psfMag = TEST_BASE_PSF_MAG + (float) i;
-            src->errMag = TEST_BASE_ERR_MAG + (float) i;
+            src->psfMagErr = TEST_BASE_ERR_MAG + (float) i;
             src->peak->flux = TEST_BASE_PEAK_FLUX + (float) i;
             src->sky = TEST_BASE_SKY + (float) i;
@@ -226,6 +226,6 @@
                 src->psfMag, (TEST_BASE_PSF_MAG + (float) i));
              float tmpF =  0.001 * PS_MIN(999, (1000 * (TEST_BASE_ERR_MAG + (float) i)));
-             ok(src->errMag == tmpF, "pmSourcesRead_SMPDATA() set src->errMag correctly (is %.2f, should be %.2f)",
-                src->errMag, tmpF);
+             ok(src->psfMagErr == tmpF, "pmSourcesRead_SMPDATA() set src->psfMagErr correctly (is %.2f, should be %.2f)",
+                src->psfMagErr, tmpF);
              tmpF = PS_MIN(99.0, (TEST_BASE_EXT_MAG + ZERO_POINT)) - ZERO_POINT;
              ok(src->extMag == tmpF, "pmSourcesRead_SMPDATA() set src->extMag correctly (is %.2f, should be %.2f)",
Index: /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourcePhotometry.c
===================================================================
--- /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourcePhotometry.c	(revision 31605)
+++ /branches/czw_branch/20110406/psModules/test/objects/tap_pmSourcePhotometry.c	(revision 31606)
@@ -103,5 +103,5 @@
     ok_float_tol(source->psfMag, fitMag, 0.0002, "source fitMag is %f", source->psfMag);
     ok_float_tol(source->apMag,  apMag, 0.0002, "source apMag is %f", source->apMag);
-    ok_float(source->errMag,   0.001, "source errMag is %f", source->errMag);
+    ok_float(source->psfMagErr,   0.001, "source psfMagErr is %f", source->psfMagErr);
     float refMag = source->apMag;
 
Index: /branches/czw_branch/20110406/psastro/src/psastroConvert.c
===================================================================
--- /branches/czw_branch/20110406/psastro/src/psastroConvert.c	(revision 31605)
+++ /branches/czw_branch/20110406/psastro/src/psastroConvert.c	(revision 31606)
@@ -133,5 +133,5 @@
         pmSource *source = sources->data[n];
 
-        psTrace ("psastro", 6, "mag: %f +/- %f, mode: %x, skip: %x\n", source->psfMag, source->errMag, source->mode, skip);
+        psTrace ("psastro", 6, "mag: %f +/- %f, mode: %x, skip: %x\n", source->psfMag, source->psfMagErr, source->mode, skip);
 
         if (source->mode & skip) {
@@ -191,5 +191,5 @@
         obj->pix->yErr = dPAR[PM_PAR_YPOS];
         obj->Mag = source->psfMag;
-        obj->dMag = source->errMag;
+        obj->dMag = source->psfMagErr;
 
         // XXX do we have the information giving the readout and cell offset?
Index: /branches/czw_branch/20110406/psconfig/psbuild
===================================================================
--- /branches/czw_branch/20110406/psconfig/psbuild	(revision 31605)
+++ /branches/czw_branch/20110406/psconfig/psbuild	(revision 31606)
@@ -386,4 +386,5 @@
     if (@ARGV != 2) { die "USAGE: psbuild -bootstrap (install_dir)\n"; }
     $psconfdir = $ARGV[1];
+    die "Target directory must be absolute, not relative: $psconfdir\n" unless $psconfdir =~ m|^/|;
 
     # copy psconfig.csh and psconfig.bash to psconfdir
Index: /branches/czw_branch/20110406/psconfig/tagsets/ipp-3.0.libs
===================================================================
--- /branches/czw_branch/20110406/psconfig/tagsets/ipp-3.0.libs	(revision 31605)
+++ /branches/czw_branch/20110406/psconfig/tagsets/ipp-3.0.libs	(revision 31606)
@@ -30,6 +30,5 @@
 lib libpthread           NONE           NONE   NONE                     NONE             N NONE NONE NONE
 lib libncurses           curses,termcap NONE   ncurses-5.6.tar.gz       ncurses-5.6      N NONE NONE NONE
-# XXX : temp for buildtest
-# lib libreadline          NONE           NONE   readline-5.2-p14.tar.gz  readline-5.2-p14 Y NONE NONE NONE
+lib libreadline          NONE           NONE   readline-5.2-p14.tar.gz  readline-5.2-p14 Y NONE NONE NONE
 lib libz                 NONE           NONE   zlib-1.2.3.tar.gz        zlib-1.2.3       N --shared NONE NONE
 lib libpng               NONE           NONE   libpng-1.2.15.tar.gz     libpng-1.2.15    N NONE NONE NONE
Index: /branches/czw_branch/20110406/psphot/src/Makefile.am
===================================================================
--- /branches/czw_branch/20110406/psphot/src/Makefile.am	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/Makefile.am	(revision 31606)
@@ -167,4 +167,5 @@
 	psphotSourcePlots.c	       \
 	psphotRadialPlot.c	       \
+	psphotKronMasked.c             \
 	psphotDeblendSatstars.c	       \
 	psphotMosaicSubimage.c	       \
Index: /branches/czw_branch/20110406/psphot/src/psphot.h
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphot.h	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphot.h	(revision 31606)
@@ -149,4 +149,7 @@
 bool            psphotPSFstats (pmReadout *readout, pmPSF *psf);
 bool            psphotMomentsStats (pmReadout *readout, psArray *sources);
+
+bool            psphotKronMasked (pmConfig *config, const pmFPAview *view, const char *filerule);
+bool            psphotKronMaskedReadout(pmConfig *config, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf);
 
 // in psphotGuessModel.c
@@ -310,5 +313,5 @@
 
 bool psphotMakeFluxScale (psImage *image, psMetadata *recipe, pmPSF *psf);
-bool psphotMakeGrowthCurve (pmReadout *readout, psMetadata *recipe, pmPSF *psf);
+bool psphotMakeGrowthCurve (pmReadout *readout, psMetadata *recipe, pmPSF *psf, psArray *sources);
 bool psphotDumpPSFStars (pmReadout *readout, pmPSFtry *try, float radius, psImageMaskType maskVal, psImageMaskType markVal);
 
Index: /branches/czw_branch/20110406/psphot/src/psphotApResid.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotApResid.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotApResid.c	(revision 31606)
@@ -1,4 +1,4 @@
 # include "psphotInternal.h"
-// # define DEBUG
+# define DEBUG
 
 # define SKIPSTAR(MSG) { psTrace ("psphot", 3, "invalid : %s", MSG); continue; }
@@ -206,5 +206,5 @@
 
         // XXX make this user-configurable?
-        if (source->errMag > 0.01) continue;
+        if (source->psfMagErr > 0.01) continue;
 
         // aperture residual for this source
@@ -222,5 +222,5 @@
                  source->peak->xf, source->peak->yf,
                  source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS],
-                 source->psfMag, source->apMag, source->errMag,
+                 source->psfMag, source->apMag, source->psfMagErr,
                  source->modelPSF->params->data.F32[PM_PAR_I0],
                  source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], source->modelPSF->params->data.F32[PM_PAR_SYY],
@@ -228,5 +228,5 @@
 # endif
         if (!isfinite(source->psfMag)) psAbort ("nan in psfMag");
-        if (!isfinite(source->errMag)) psAbort ("nan in errMag");
+        if (!isfinite(source->psfMagErr)) psAbort ("nan in psfMagErr");
         if (!isfinite(source->apMag)) psAbort ("nan in apMag");
         if (!isfinite(model->params->data.F32[PM_PAR_XPOS])) psAbort ("nan in xPos");
@@ -234,5 +234,5 @@
 
         psVectorAppend (mag, source->psfMag);
-        psVectorAppend (dMag,source->errMag);
+        psVectorAppend (dMag,source->psfMagErr);
         psVectorAppend (apResid, dap);
         psVectorAppend (xPos, model->params->data.F32[PM_PAR_XPOS]);
@@ -328,5 +328,21 @@
     psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_META_REPLACE, "ap residual scatter", psf->dApResid);
     psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_META_REPLACE, "number of apresid stars", psf->nApResid);
-    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", psf->growth ? psf->growth->apLoss : NAN);
+
+    // curve-of-growth offset
+    if (psf->growth) {
+	float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
+	if (!status) {
+	    gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
+	}
+	float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
+	float PSF_APERTURE = (int)(apScale*gaussSigma);
+	
+	float offset = pmGrowthCurveCorrect (psf->growth, PSF_APERTURE);
+	psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
+	psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APREFOFF", PS_META_REPLACE, "offset to ref aperture", offset);
+    } else {
+	psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", NAN);
+	psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APREFOFF", PS_META_REPLACE, "offset to ref aperture", NAN);
+    }
 
     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
Index: /branches/czw_branch/20110406/psphot/src/psphotBlendFit.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotBlendFit.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotBlendFit.c	(revision 31606)
@@ -242,4 +242,7 @@
         if (source->mode &  PM_SOURCE_MODE_PAIR) continue;
 
+	// do not include MOMENTS_FAILURES in the fit
+        if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) continue;
+
         // limit selection to some SN limit
         if (sqrt(source->peak->detValue) < FIT_SN_LIM) continue;
@@ -280,8 +283,6 @@
         if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
             if (psphotFitBlob (readout, source, newSources, psf, fitOptions, maskVal, markVal)) {
-                source->type = PM_SOURCE_TYPE_EXTENDED;
                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
                 Next ++;
-                source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
                 continue;
             }
@@ -291,5 +292,4 @@
                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
                 Npsf ++;
-                source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
                 continue;
             }
Index: /branches/czw_branch/20110406/psphot/src/psphotChoosePSF.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotChoosePSF.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotChoosePSF.c	(revision 31606)
@@ -350,5 +350,5 @@
 
     // build curve-of-growth vector for this psf
-    if (!psphotMakeGrowthCurve (readout, recipe, try->psf)) {
+    if (!psphotMakeGrowthCurve (readout, recipe, try->psf, try->sources)) {
         psError(PSPHOT_ERR_PSF, false, "Unable to construct flux scale for PSF");
         psFree (models);
Index: /branches/czw_branch/20110406/psphot/src/psphotEfficiency.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotEfficiency.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotEfficiency.c	(revision 31606)
@@ -400,4 +400,7 @@
                 source->type = PM_SOURCE_TYPE_STAR;
 
+		source->modelPSF->fitRadius = sourceRadius;
+		source->apRadius = sourceRadius;
+
                 numFound++;
                 psArrayAdd(sources, sources->n, source);
@@ -468,8 +471,8 @@
                     source->modelPSF->params->data.F32[PM_PAR_XPOS],
                     source->modelPSF->params->data.F32[PM_PAR_YPOS],
-                    magRef, source->psfMag, source->errMag);
+                    magRef, source->psfMag, source->psfMagErr);
 #endif
             magDiff->data.F32[j] = source->psfMag - magRef;
-            magErr->data.F32[j] = source->errMag;
+            magErr->data.F32[j] = source->psfMagErr;
         }
         magDiff->n = sources->n;
Index: /branches/czw_branch/20110406/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotExtendedSourceFits.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotExtendedSourceFits.c	(revision 31606)
@@ -333,5 +333,5 @@
 	// this uses the footprint to judge both radius and aperture?
 	// XXX save the psf-based moments for output
-	if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) {
+	if (!pmSourceMoments (source, radius, 0.0, 0.0, 0.0, maskVal)) {
 	    fprintf (stderr, "skipping (2) %f, %f\n", source->peak->xf, source->peak->yf);
 	    // subtract the best fit from the object, leave local sky
@@ -379,8 +379,6 @@
           assert (status);
 
-	  // fprintf (stderr, "xfit: %f, %f : %f\n", source->peak->xf, source->peak->yf, source->peak->SN); 
-
           // limit selection to some SN limit
-          assert (source->peak); // how can a source not have a peak?
+          // assert (source->peak); // how can a source not have a peak?
           if (sqrt(source->peak->detValue) < SNlim) {
 	      Nfaint ++;
Index: /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinear.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinear.c	(revision 31606)
@@ -137,4 +137,7 @@
         if (source->mode & PM_SOURCE_MODE_CR_LIMIT) continue;
 
+	// do not include MOMENTS_FAILURES in the fit
+        if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) continue;
+
 	// XXX count saturated stars
         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
@@ -164,23 +167,37 @@
 
 	// check the integral of the model : is it large enough?
+	// apply mask?
 	float modelSum = 0.0;
+	float maskedSum = 0.0;
 	for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
 	    for (int ix = 0; ix < source->modelFlux->numCols; ix++) {
 		modelSum += source->modelFlux->data.F32[iy][ix];
+		if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) continue;
+		maskedSum += source->modelFlux->data.F32[iy][ix];
 	    }
 	}
 	if (modelSum < 0.5) continue; // skip sources with no model constraint (somewhat arbitrary limit)
-	// if (modelSum < 0.01) continue; // skip sources with no model constraint (somewhat arbitrary limit)
 	if (modelSum < 0.8) {
-	    fprintf (stderr, "low-sig model @ %f, %f (%f sum, %f peak)\n",
-		     source->peak->xf, source->peak->yf, modelSum, source->peak->rawFlux);
+	    fprintf (stderr, "low-sig model @ %f, %f (%f masked sum, %f sum, %f peak)\n",
+		     source->peak->xf, source->peak->yf, maskedSum, modelSum, source->peak->rawFlux);
 	}
-
-        pmModel *model = pmSourceGetModel (NULL, source);
+	if (maskedSum < 0.5) {
+	    fprintf (stderr, "worrying model @ %f, %f (%f masked sum, %f sum, %f peak)\n",
+		     source->peak->xf, source->peak->yf, maskedSum, modelSum, source->peak->rawFlux);
+	}
+
+	bool isPSF = false;
+        pmModel *model = pmSourceGetModel (&isPSF, source);
 
         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, model->fitRadius, "OR", markVal);
 
-        source->mode |= PM_SOURCE_MODE_LINEAR_FIT;
+	// we call this function multiple times. for the first time, we have only PSF models for all objects
+	// the second time has extended sources.  If we ever fit the PSF model, we should raise this bit
+	source->mode |= PM_SOURCE_MODE_LINEAR_FIT;
+	if (isPSF) {
+	    source->mode |= PM_SOURCE_MODE_PSFMODEL;
+	}	    
+	
         psArrayAdd (fitSources, 100, source);
     }
@@ -260,4 +277,33 @@
         }
     }
+
+# if (0)
+    static int npass = 0;
+    char name[128];
+    FILE *f1 = NULL;
+    int fd = -1;
+
+    snprintf (name, 128, "sparse.Aij.%02d.dat", npass);
+    f1 = fopen (name, "w");
+    psAssert (f1, "failed to open file\n");
+    fd = fileno (f1);
+    p_psVectorPrint (fd, sparse->Aij, "Aij");
+    fclose (f1);
+
+    snprintf (name, 128, "sparse.Bfj.%02d.dat", npass);
+    f1 = fopen (name, "w");
+    psAssert (f1, "failed to open file\n");
+    fd = fileno (f1);
+    p_psVectorPrint (fd, sparse->Bfj, "Bfj");
+    fclose (f1);
+
+    snprintf (name, 128, "sparse.Qii.%02d.dat", npass);
+    f1 = fopen (name, "w");
+    psAssert (f1, "failed to open file\n");
+    fd = fileno (f1);
+    p_psVectorPrint (fd, sparse->Qii, "Qii");
+    fclose (f1);
+    npass ++;
+# endif
 
     psSparseResort (sparse);
Index: /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinearStack.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinearStack.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotFitSourcesLinearStack.c	(revision 31606)
@@ -69,4 +69,17 @@
             if (!pmSourceCacheModel (source, maskVal)) continue;
           }
+
+	  // check the integral of the model : is it large enough?
+	  float modelSum = 0.0;
+	  for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
+	      for (int ix = 0; ix < source->modelFlux->numCols; ix++) {
+		  modelSum += source->modelFlux->data.F32[iy][ix];
+	      }
+	  }
+	  if (modelSum < 0.5) continue; // skip sources with no model constraint (somewhat arbitrary limit)
+	  if (modelSum < 0.8) {
+	      fprintf (stderr, "low-sig model @ %f, %f (%f sum, %f peak)\n",
+		       source->peak->xf, source->peak->yf, modelSum, source->peak->rawFlux);
+	  }
 
           source->mode |= PM_SOURCE_MODE_LINEAR_FIT;
Index: /branches/czw_branch/20110406/psphot/src/psphotGuessModels.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotGuessModels.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotGuessModels.c	(revision 31606)
@@ -160,8 +160,4 @@
         pmSource *source = sources->data[i];
 
-        if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) {
-	    fprintf (stderr, "moment failure\n");
-	}
-
         // this is used to mark sources for which the model is measured. We check later that
         // all are used.
@@ -169,4 +165,5 @@
 
         // skip non-astronomical objects (very likely defects)
+        if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) continue;
         if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
         if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
@@ -196,4 +193,5 @@
         }
 
+# if (0)
 	if (source->mode & PM_SOURCE_MODE_SATSTAR) {
 	    fprintf (stderr, "satstar: %f,%f vs %f,%f : %c\n", 
@@ -202,4 +200,5 @@
 		     (useMoments ? 'T' : 'F'));
 	}
+# endif
 
         // set PSF parameters for this model (apply 2D shape model to coordinates Xo, Yo)
Index: /branches/czw_branch/20110406/psphot/src/psphotKronMasked.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotKronMasked.c	(revision 31606)
+++ /branches/czw_branch/20110406/psphot/src/psphotKronMasked.c	(revision 31606)
@@ -0,0 +1,273 @@
+# include "psphotInternal.h"
+
+bool psphotKronMag (pmSource *source, float radius, psImageMaskType maskVal);
+
+bool psphotKronMasked (pmConfig *config, const pmFPAview *view, const char *filerule)
+{
+    bool status = true;
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
+
+    int num = psphotFileruleCount(config, filerule);
+
+    // skip the chisq image (optionally?)
+    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
+    if (!status) chisqNum = -1;
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+        if (i == chisqNum) continue; // skip chisq image
+
+        // find the currently selected readout
+        pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, i); // File of interest
+        psAssert (file, "missing file?");
+
+        pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+        psAssert (readout, "missing readout?");
+
+        pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
+        psAssert (detections, "missing detections?");
+
+        psArray *sources = detections->allSources;
+        psAssert (sources, "missing sources?");
+
+        pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
+        // psAssert (psf, "missing psf?");
+
+        if (!psphotKronMaskedReadout (config, recipe, view, readout, sources, psf)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed to measure magnitudes for %s entry %d", filerule, i);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool psphotKronMaskedReadout(pmConfig *config, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf) {
+
+    bool status = false;
+
+    if (!sources->n) {
+        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping masked kron");
+        return true;
+    }
+
+    psTimerStart ("psphot.kron");
+
+    // determine the number of allowed threads
+    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
+    if (!status) {
+        nThreads = 0;
+    }
+
+    float RADIUS = psMetadataLookupF32 (&status, readout->analysis, "PSF_MOMENTS_RADIUS");
+    if (!status) {
+        RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
+    }
+
+    // bit-masks to test for good/bad pixels
+    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
+    assert (maskVal);
+
+    // bit-mask to mark pixels not used in analysis
+    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // generate the mask image: increment counter for every source overlapping the pixel
+    psImage *kronMask = psImageAlloc (readout->image->numCols, readout->image->numRows, PS_TYPE_U8);
+    psImageInit (kronMask, 0);
+    int Nx = kronMask->numCols;
+    int Ny = kronMask->numRows;
+    for (int i = 0; i < sources->n; i++) {
+
+        pmSource *source = sources->data[i];
+        if (!source->peak) continue; // XXX how can we have a peak-less source?
+
+        // allocate space for moments
+        if (!source->moments) continue;
+
+        // replace object in image
+        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+        }
+
+	psphotKronMag (source, RADIUS, maskVal);
+
+        // re-subtract the object, leave local sky
+        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+
+	continue;
+
+	// XXX skip this code
+	// generate the pixel masks
+	// int Xo = source->moments->Mx;
+	// int Yo = source->moments->My;
+	float dX = source->moments->Mx - source->peak->xf;
+	float dY = source->moments->My - source->peak->yf;
+	float dR = hypot(dX, dY);
+	
+	float Xo = (dR < 2.0) ? source->moments->Mx : source->peak->xf;
+	float Yo = (dR < 2.0) ? source->moments->My : source->peak->yf;
+	
+	int Kr = 2.5*source->moments->Mrf;
+	int Kr2 = Kr*Kr;
+	
+	for (int iy = Yo - Kr; iy < Yo + Kr + 1; iy++) {
+	    if (iy < 0) continue;
+	    if (iy >= Ny) continue;
+	    for (int ix = Xo - Kr; ix < Xo + Kr + 1; ix++) {
+		if (ix < 0) continue;
+		if (ix >= Nx) continue;
+
+		if (PS_SQR(ix - Xo) + PS_SQR(iy - Yo) > Kr2) continue;
+		if (kronMask->data.U8[iy][ix] < 0xff) {
+		    kronMask->data.U8[iy][ix] ++;
+		}
+	    }
+	}
+    }		
+    // psphotSaveImage (NULL, kronMask, "kronmask.fits");
+    psLogMsg ("psphot.kron", PS_LOG_DETAIL, "measure masked kron magnitudes : %f sec for %ld objects\n", psTimerMark ("psphot.kron"), sources->n);
+
+    psFree (kronMask);
+    return true;
+}
+
+bool psphotKronMag (pmSource *source, float radius, psImageMaskType maskVal) {
+
+    PS_ASSERT_PTR_NON_NULL(source, false);
+    PS_ASSERT_PTR_NON_NULL(source->peak, false);
+    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
+    PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
+
+    psF32 Sum = 0.0;
+    psF32 Var = 0.0;
+    psF32 R2 = PS_SQR(radius);
+
+    // a note about coordinates: coordinates of objects throughout psphot refer to the primary
+    // image coordinates.  the source->pixels image has an offset relative to its parent of
+    // col0,row0: a pixel (x,y) in the primary image has coordinates of (x-col0, y-row0) in
+    // this subimage.  we subtract off the peak coordinates, adjusted to this subimage, to have
+    // minimal round-off error in the sums.  since these values are subtracted just to minimize
+    // the dynamic range and are added back below, the exact value does not matter. these are
+    // (int) so they can be used in the image index below.
+
+    // Now calculate higher-order moments, using the above-calculated first moments to adjust coordinates
+    // Xn  = SUM (x - xc)^n * (z - sky)
+
+    psF32 RF = 0.0;
+    psF32 RS = 0.0;
+
+# if (1)
+    float dX = source->moments->Mx - source->peak->xf;
+    float dY = source->moments->My - source->peak->yf;
+    float dR = hypot(dX, dY);
+    float Xo = (dR < 2.0) ? source->moments->Mx : source->peak->xf;
+    float Yo = (dR < 2.0) ? source->moments->My : source->peak->yf;
+# else
+    float Xo = source->moments->Mx;
+    float Yo = source->moments->My;
+# endif
+
+    // center of mass in subimage.  Note: the calculation below uses pixel index, so we correct
+    // xCM, yCM from pixel coords to pixel index here.
+    psF32 xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage
+    psF32 yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage
+
+    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
+
+	psF32 yDiff = row - yCM;
+	if (fabs(yDiff) > radius) continue;
+
+	psF32 *vPix = source->pixels->data.F32[row];
+
+	psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+
+	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++) {
+	    if (vMsk) {
+		if (*vMsk & maskVal) {
+		    vMsk++;
+		    continue;
+		}
+		vMsk++;
+	    }
+	    if (isnan(*vPix)) continue;
+
+	    psF32 xDiff = col - xCM;
+	    if (fabs(xDiff) > radius) continue;
+
+	    // radius is just a function of (xDiff, yDiff)
+	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    if (r2 > R2) continue;
+
+	    psF32 pDiff = *vPix;
+
+	    Sum += pDiff;
+
+	    // Kron Flux uses the 1st radial moment (NOT Gaussian windowed)
+	    psF32 rf = pDiff * sqrt(r2);
+	    psF32 rs = pDiff;
+
+	    RF  += rf;
+	    RS  += rs;
+	}
+    }
+
+    // Saturate the 1st radial moment
+    float Mrf = MIN(radius, MAX(0.25*radius, RF/RS));
+
+    // Calculate the Kron magnitude (make this block optional?)
+    float radKron  = 2.5*Mrf;
+    float radKron2 = radKron*radKron;
+
+    int nKronPix = 0;
+    Sum = Var = 0.0;
+
+    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
+
+	psF32 yDiff = row - yCM;
+	if (fabs(yDiff) > radKron) continue;
+
+	psF32 *vPix = source->pixels->data.F32[row];
+	psF32 *vWgt = source->variance->data.F32[row];
+
+	psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+
+	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
+	    if (vMsk) {
+		if (*vMsk & maskVal) {
+		    vMsk++;
+		    continue;
+		}
+		vMsk++;
+	    }
+	    if (isnan(*vPix)) continue;
+
+	    psF32 xDiff = col - xCM;
+	    if (fabs(xDiff) > radKron) continue;
+
+	    // radKron is just a function of (xDiff, yDiff)
+	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    if (r2 > radKron2) continue;
+
+	    psF32 pDiff = *vPix;
+	    psF32 wDiff = *vWgt;
+
+	    Sum += pDiff;
+	    Var += wDiff;
+	    nKronPix ++;
+	}
+    }
+    // XXX for a test, save the old values here:
+    source->moments->KronCore    = source->moments->KronFlux;
+    source->moments->KronCoreErr = source->moments->KronFluxErr;
+
+    source->moments->KronFlux    = Sum       * M_PI * PS_SQR(radKron) / nKronPix;
+    source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix;
+
+    return true;
+}
Index: /branches/czw_branch/20110406/psphot/src/psphotLoadSRCTEXT.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotLoadSRCTEXT.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotLoadSRCTEXT.c	(revision 31606)
@@ -52,5 +52,5 @@
 
 	    // NOTE: most of these values are irrelevant for loaded source positions
-	    source->seq       = 0;
+	    source->seq       = source->id;
 	    PAR[PM_PAR_XPOS]  = X;
 	    PAR[PM_PAR_YPOS]  = Y;
@@ -67,5 +67,5 @@
 
 	    source->psfMag    = 0.0;
-	    source->errMag    = 0.0;
+	    source->psfMagErr    = 0.0;
 	    source->apMag     = 0.0;
 
Index: /branches/czw_branch/20110406/psphot/src/psphotMagnitudes.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotMagnitudes.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotMagnitudes.c	(revision 31606)
@@ -167,4 +167,18 @@
         pmSource *source = (pmSource *) sources->data[i];
 
+	bool saveTest = false;
+	psImage *testImage = NULL;
+# if (0)
+	if ((fabs(source->peak->xf-3518) < 5) && (fabs(source->peak->yf-3178) < 5)) {
+	    saveTest = true;
+	    psRegion subregion = psRegionSet (source->peak->xf - 200, source->peak->xf + 200, source->peak->yf - 200, source->peak->yf + 200);
+	    testImage = psImageSubset ((psImage *) source->pixels->parent, subregion);
+	}
+# endif
+
+	if (saveTest) {
+	    psphotSaveImage(NULL, testImage, "test.image.1.fits");
+	}
+
         // replace object in image
         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
@@ -172,10 +186,33 @@
         }
 
+	if (saveTest) {
+	    psphotSaveImage(NULL, testImage, "test.image.2.fits");
+	}
+
+	float xPos = source->peak->xf;
+	float yPos = source->peak->yf;
+
+	pmModel *model = source->modelPSF;
+	if (model) {
+	    xPos = model->params->data.F32[PM_PAR_XPOS];
+	    yPos = model->params->data.F32[PM_PAR_YPOS];
+	} else {
+	    bool useMoments = pmSourcePositionUseMoments(source);
+	    if (useMoments) {
+		xPos = source->moments->Mx;
+		yPos = source->moments->My;
+	    }
+	}
+
         // clear the mask bit and set the circular mask pixels
         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
+        psImageKeepCircle (source->maskObj, xPos, yPos, source->apRadius, "OR", markVal);
 
         status = pmSourceMagnitudes (source, psf, photMode, maskVal, markVal, source->apRadius);
-        if (status && isfinite(source->apMag)) Nap ++;
+        if (status && isfinite(source->apFlux)) {
+	    Nap ++;
+	} else {
+	    fprintf (stderr, "failed to measure mag for source @ %f,%f\n", source->peak->xf, source->peak->yf);
+	}
 
         // clear the mask bit
@@ -185,7 +222,11 @@
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
+	if (saveTest) {
+	    psphotSaveImage(NULL, testImage, "test.image.3.fits");
+	}
+
         if (backModel) {
             psAssert (binning, "if backModel is defined, so should binning be");
-            source->sky = psImageUnbinPixel(source->peak->x, source->peak->y, backModel->image, binning);
+            source->sky = psImageUnbinPixel(xPos, yPos, backModel->image, binning);
             if (isnan(source->sky) && false) {
                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.sky");
@@ -197,5 +238,5 @@
         if (backStdev) {
             psAssert (binning, "if backStdev is defined, so should binning be");
-            source->skyErr = psImageUnbinPixel(source->peak->x, source->peak->y, backStdev->image, binning);
+            source->skyErr = psImageUnbinPixel(xPos, yPos, backStdev->image, binning);
             if (isnan(source->skyErr) && false) {
                 psLogMsg ("psphot.magnitudes", PS_LOG_DETAIL, "error setting pmSource.skyErr");
Index: /branches/czw_branch/20110406/psphot/src/psphotMakeGrowthCurve.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotMakeGrowthCurve.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotMakeGrowthCurve.c	(revision 31606)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotMakeGrowthCurve (pmReadout *readout, psMetadata *recipe, pmPSF *psf) {
+bool psphotMakeGrowthCurve (pmReadout *readout, psMetadata *recipe, pmPSF *psf, psArray *sources) {
 
     bool status;
@@ -22,18 +22,41 @@
 
     // measure the aperture loss as a function of radius for PSF
-    bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
     float REF_RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_REF_RADIUS");
     float PSF_FIT_PAD   = psMetadataLookupF32 (&status, recipe, "PSF_FIT_PADDING");
+    
+    float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
+    if (!status) {
+	gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
+    }
+    float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
+    float PSF_APERTURE = (int)(apScale*gaussSigma);
 
     psf->growth = pmGrowthCurveAlloc (PSF_FIT_PAD, 100.0, REF_RADIUS);
 
-    if (!pmGrowthCurveGenerate (readout, psf, IGNORE_GROWTH, maskVal, markVal)) {
-        psError(PSPHOT_ERR_APERTURE, false, "Fitting aperture corrections");
-        psFree(psf->growth); psf->growth = NULL;
-        return false;
+    bool GROWTH_FROM_SOURCES = psMetadataLookupBool (&status, recipe, "GROWTH_FROM_SOURCES");
+    if (!status) GROWTH_FROM_SOURCES = false;
+
+    if (GROWTH_FROM_SOURCES) {
+	bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
+	if (!pmGrowthCurveGenerateFromSources (readout, psf, sources, INTERPOLATE_AP, maskVal, markVal)) {
+	    psError(PSPHOT_ERR_APERTURE, false, "Fitting aperture corrections");
+	    psFree(psf->growth); psf->growth = NULL;
+	    return false;
+	}
+
+    } else {
+	bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
+	if (!pmGrowthCurveGenerate (readout, psf, IGNORE_GROWTH, maskVal, markVal)) {
+	    psError(PSPHOT_ERR_APERTURE, false, "Fitting aperture corrections");
+	    psFree(psf->growth); psf->growth = NULL;
+	    return false;
+	}
     }
 
     psLogMsg ("psphot", PS_LOG_MINUTIA, "built growth curve: %f sec\n", psTimerMark ("psphot.growth"));
 
+    float offset = pmGrowthCurveCorrect (psf->growth, PSF_APERTURE);
+    psLogMsg ("psphot", PS_LOG_DETAIL, "correction from %f to %f: %f mags\n", PSF_APERTURE, REF_RADIUS, offset);
+
     return true;
 }
Index: /branches/czw_branch/20110406/psphot/src/psphotMergeSources.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotMergeSources.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotMergeSources.c	(revision 31606)
@@ -137,4 +137,9 @@
                 pmSource *source = extSourcesTXT->data[i];
                 source->mode |= PM_SOURCE_MODE_EXTERNAL;
+
+                // the supplied peak flux needs to be re-normalized
+                source->peak->rawFlux = 1.0;
+                source->peak->smoothFlux = 1.0;
+                source->peak->detValue = 1.0;
 
                 // drop the loaded source modelPSF
Index: /branches/czw_branch/20110406/psphot/src/psphotModelTest.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotModelTest.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotModelTest.c	(revision 31606)
@@ -226,5 +226,5 @@
     // measure the source mags
     pmSourcePhotometryModel (&fitMag, model);
-    pmSourcePhotometryAper  (&obsMag, NULL, NULL, model, source->pixels, source->variance, source->maskObj, maskVal);
+    pmSourcePhotometryAper  (NULL, &obsMag, NULL, NULL, model, source->pixels, source->variance, source->maskObj, maskVal);
     fprintf (stderr, "ap: %f, fit: %f, apmifit: %f, nIter: %d\n", obsMag, fitMag, obsMag - fitMag, model->nIter);
 
Index: /branches/czw_branch/20110406/psphot/src/psphotOutput.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotOutput.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotOutput.c	(revision 31606)
@@ -75,5 +75,5 @@
 		 source->peak->xf, source->peak->yf, 
 		 model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS], 
-		 source->psfMag, source->apMag, source->errMag,
+		 source->psfMag, source->apMag, source->psfMagErr,
 		 model->params->data.F32[PM_PAR_I0], 
 		 model->params->data.F32[PM_PAR_SXX], model->params->data.F32[PM_PAR_SXY], model->params->data.F32[PM_PAR_SYY], 
@@ -251,4 +251,5 @@
     psMetadataItemSupplement (&status, header, analysis, "NPSFSTAR");
     psMetadataItemSupplement (&status, header, analysis, "APLOSS");
+    psMetadataItemSupplement (&status, header, analysis, "APREFOFF");
 
     psMetadataItemSupplement (&status, header, analysis, "FWHM_MAJ");
Index: /branches/czw_branch/20110406/psphot/src/psphotPetrosianStats.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotPetrosianStats.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotPetrosianStats.c	(revision 31606)
@@ -163,5 +163,5 @@
 	if (refRadius->data.F32[i] > apRadius) {
 	    if (i == 0) {
-		psWarning ("does this case make any sense? (refRadius[0] > apRadius)");
+		psWarning ("does this case make any sense? (refRadius[0] %f > apRadius %f)", refRadius->data.F32[i], apRadius);
 		continue;
 	    } else {
@@ -188,5 +188,5 @@
 	if (!found50 && (fluxSum->data.F32[i] > flux50)) {
 	    if (i == 0) {
-		psWarning ("does this case make any sense? (fluxSum[0] > flux50)");
+		psWarning ("does this case make any sense? (fluxSum[0] %f > flux50 %f)", fluxSum->data.F32[i], flux50);
 		continue;
 	    } else {
@@ -198,5 +198,5 @@
 	if (!found90 && (fluxSum->data.F32[i] > flux90)) {
 	    if (i == 0) {
-		psWarning ("does this case make any sense? (fluxSum[0] > flux90)");
+		psWarning ("does this case make any sense? (fluxSum[0] %f > flux90 %f)", fluxSum->data.F32[i], flux90);
 		continue;
 	    } else {
Index: /branches/czw_branch/20110406/psphot/src/psphotRadialApertures.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotRadialApertures.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotRadialApertures.c	(revision 31606)
@@ -95,5 +95,7 @@
 	if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
 	if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
-	if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
+
+	// XXX measure radial apertures even for saturated stars
+	// if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
 
 	// limit selection to some SN limit
@@ -257,9 +259,12 @@
 	float SBstdv = sqrt((fluxStd->data.F32[i] / nPix) - PS_SQR(SBmean));
 
+	// XXX report the total flux or the mask-corrected flux?
 	// flux->data.F32[i]    = SBmean * Area;
+	// fluxErr->data.F32[i] = sqrt(fluxErr->data.F32[i]) * Area / nPix;
+
+	fluxErr->data.F32[i] = sqrt(fluxErr->data.F32[i]);
 	fluxStd->data.F32[i] = SBstdv * Area;
-	fluxErr->data.F32[i] = sqrt(fluxErr->data.F32[i]) * Area / nPix;
-
-	// fill->data.F32[i] /= Area;
+	fill->data.F32[i] /= Area;
+
 	psTrace ("psphot", 5, "radial bins: %3d  %5.1f : %8.1f +/- %7.2f : %8.1f +/- %8.1f : %4.2f %6.1f\n", 
 		 i, aperRadii->data.F32[i], flux->data.F32[i], fluxErr->data.F32[i], SBmean, SBstdv, fill->data.F32[i], Area);
Index: /branches/czw_branch/20110406/psphot/src/psphotRadiusChecks.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotRadiusChecks.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotRadiusChecks.c	(revision 31606)
@@ -184,8 +184,5 @@
 bool psphotSetRadiusModel (pmModel *model, pmReadout *readout, pmSource *source, psImageMaskType markVal, bool deep) {
 
-    psF32 *PAR = model->params->data.F32;
-
-    pmMoments *moments = source->moments;
-    if (moments == NULL) return false;
+    pmPeak *peak = source->peak;
 
     // set the fit radius based on the object flux limit and the model
@@ -199,8 +196,8 @@
 
     // redefine the pixels if needed
-    pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
-
-    // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
-    return true;
-}
+    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, model->fitRadius);
+
+    // set the mask to flag the excluded pixels
+    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, model->fitRadius, "OR", markVal);
+    return true;
+}
Index: /branches/czw_branch/20110406/psphot/src/psphotReadout.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotReadout.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotReadout.c	(revision 31606)
@@ -200,4 +200,7 @@
     psphotDumpChisqs (config, view, filerule);
 
+    // XXX re-measure the kron mags with models subtracted
+    psphotKronMasked(config, view, filerule);
+
     // identify CRs and extended sources (only unmeasured sources are measured)
     psphotSourceSize (config, view, filerule, true); // pass 1 (detections->allSources)
@@ -309,4 +312,7 @@
 pass1finish:
 
+    // XXX re-measure the kron mags with models subtracted
+    psphotKronMasked(config, view, filerule);
+
     // measure source size for the remaining sources
     // NOTE: applies only to NEW (unmeasured) sources
@@ -345,16 +351,12 @@
       psErrorStackPrint(stderr, "Unable to replace sky");
       psErrorClear();
-
-/*       psLogMsg("psphot", 3, "failed on psphotSkyReplace"); */
-/*       return(psphotReadoutCleanup(config, view, filerule)); */
-    }
+    }
+
     // drop the references to the image pixels held by each source
     if (!psphotSourceFreePixels (config, view, filerule)) { // pass 1
       psErrorStackPrint(stderr, "Unable to free source pixels");
       psErrorClear();
-
-/*       psLogMsg ("psphot", 3, "failed on psphotSourceFreePixels"); */
-/*       return(psphotReadoutCleanup(config, view, filerule)); */
-    }
+    }
+
     // create the exported-metadata and free local data
     return psphotReadoutCleanup(config, view, filerule);
Index: /branches/czw_branch/20110406/psphot/src/psphotReplaceUnfit.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotReplaceUnfit.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotReplaceUnfit.c	(revision 31606)
@@ -67,4 +67,11 @@
     psAssert (maskVal, "missing mask value?");
 
+    // bit-mask to mark pixels not used in analysis
+    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
     for (int i = 0; i < sources->n; i++) {
       source = sources->data[i];
Index: /branches/czw_branch/20110406/psphot/src/psphotRoughClass.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotRoughClass.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotRoughClass.c	(revision 31606)
@@ -207,5 +207,9 @@
         return false;
     }
-    psLogMsg ("psphot", 3, "psf clump  X,  Y: %f, %f : DX, DY: %f, %f : nStars %d of %d\n", psfClump.X, psfClump.Y, psfClump.dX, psfClump.dY, psfClump.nStars, psfClump.nTotal);
+    if (!havePSF) {
+	psLogMsg ("psphot", 3, "psf clump  X,  Y: %f, %f : DX, DY: %f, %f : nStars %d of %d\n", psfClump.X, psfClump.Y, psfClump.dX, psfClump.dY, psfClump.nStars, psfClump.nTotal);
+    } else {
+	psLogMsg ("psphot", 3, "psf clump  X,  Y: %f, %f : DX, DY: %f, %f : loaded from metadata\n", psfClump.X, psfClump.Y, psfClump.dX, psfClump.dY);
+    }
 
     // get basic parameters, or set defaults
Index: /branches/czw_branch/20110406/psphot/src/psphotSetThreads.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotSetThreads.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotSetThreads.c	(revision 31606)
@@ -25,5 +25,5 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_SOURCE_STATS", 10);
+    task = psThreadTaskAlloc("PSPHOT_SOURCE_STATS", 11);
     task->function = &psphotSourceStats_Threaded;
     psThreadTaskAdd(task);
Index: /branches/czw_branch/20110406/psphot/src/psphotSourceFits.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotSourceFits.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotSourceFits.c	(revision 31606)
@@ -146,4 +146,5 @@
     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     source->mode |=  PM_SOURCE_MODE_BLEND_FIT;
+    source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
     return true;
 }
@@ -186,4 +187,5 @@
 
     // build cached model and subtract
+    source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
     pmSourceCacheModel (source, maskVal);
     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
@@ -233,5 +235,5 @@
     // XXX save the psf-based moments for output
     psfMoments = *source->moments;
-    if (!pmSourceMoments (source, radius, 0.0, 0.5, maskVal)) {
+    if (!pmSourceMoments (source, radius, 0.0, 0.5, 0.0, maskVal)) {
       *source->moments = psfMoments;
       return false;
@@ -319,4 +321,5 @@
     source->type = PM_SOURCE_TYPE_EXTENDED;
     source->mode |= PM_SOURCE_MODE_EXTMODEL;
+    source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
 
     // build cached model and subtract
@@ -346,4 +349,5 @@
     source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
     source->mode     |= PM_SOURCE_MODE_PAIR;
+    source->mode |= PM_SOURCE_MODE_NONLINEAR_FIT;
 
     // copy most data from the primary source (modelEXT, blends stay NULL)
@@ -489,5 +493,5 @@
     // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     pmSourceFitModel (source, model, &options, maskVal);
-    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
 
     // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
@@ -554,5 +558,5 @@
     // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
     pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
-    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
 
     // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
Index: /branches/czw_branch/20110406/psphot/src/psphotSourceSize.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotSourceSize.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotSourceSize.c	(revision 31606)
@@ -213,5 +213,5 @@
 
         psVectorAppend (ApOff, dMag);
-        psVectorAppend (ApErr, source->errMag);
+        psVectorAppend (ApErr, source->psfMagErr);
     }
     if (num == 0) {
@@ -520,5 +520,5 @@
         // set nSigmaMAG to include both systematic and poisson error terms.  we include a hard
 	// floor on the Ap Sys Err (to be a bit generous).  XXX put the floor in the recipe...
-        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.02));
+        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->psfMagErr, hypot(options->ApSysErr, 0.02));
         source->extNsigma = nSigmaMAG;
 
Index: /branches/czw_branch/20110406/psphot/src/psphotSourceStats.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotSourceStats.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotSourceStats.c	(revision 31606)
@@ -98,6 +98,8 @@
 
     // generate the array of sources, define the associated pixel
+    bool firstPass = false;
     if (!detections->newSources) {
         detections->newSources = psArrayAllocEmpty (peaks->n);
+	firstPass = true;
     }
     sources = detections->newSources;
@@ -125,4 +127,8 @@
         if (source->mode & PM_SOURCE_MODE_MOMENTS_FAILURE) {
 	    fprintf (stderr, "moment failure\n");
+	}
+
+	if (firstPass) {
+            source->mode2 |= PM_SOURCE_MODE2_PASS1_SRC;
 	}
 
@@ -159,4 +165,8 @@
         RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     }
+    float MIN_KRON_RADIUS = psMetadataLookupF32 (&status, readout->analysis, "MOMENTS_MIN_KRON");
+    if (!status) {
+        MIN_KRON_RADIUS = 0.75*SIGMA;
+    }
 
     // threaded measurement of the source magnitudes
@@ -186,4 +196,5 @@
             PS_ARRAY_ADD_SCALAR(job->args, RADIUS,  PS_TYPE_F32);
             PS_ARRAY_ADD_SCALAR(job->args, SIGMA,   PS_TYPE_F32);
+            PS_ARRAY_ADD_SCALAR(job->args, MIN_KRON_RADIUS, PS_TYPE_F32);
 
             PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
@@ -215,9 +226,9 @@
             } else {
                 psScalar *scalar = NULL;
-                scalar = job->args->data[7];
+                scalar = job->args->data[8];
                 Nmoments += scalar->data.S32;
-                scalar = job->args->data[8];
+                scalar = job->args->data[9];
                 Nfail += scalar->data.S32;
-                scalar = job->args->data[9];
+                scalar = job->args->data[10];
                 Nfaint += scalar->data.S32;
             }
@@ -231,4 +242,7 @@
 
     psphotVisualShowMoments (sources);
+
+    // clear the mark bits
+    // psImageMaskPixels (readout->mask, "AND", PS_NOT_IMAGE_MASK(markVal));
 
     if (detections->allSources) {
@@ -373,7 +387,8 @@
     float RADIUS                    = PS_SCALAR_VALUE(job->args->data[3],F32);
     float SIGMA                     = PS_SCALAR_VALUE(job->args->data[4],F32);
-
-    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
-    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
+    float MIN_KRON_RADIUS           = PS_SCALAR_VALUE(job->args->data[5],F32);
+
+    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[7],PS_TYPE_IMAGE_MASK_DATA);
 
     // if no valid pixels, massive swing or very large Mrf, likely saturated source,
@@ -431,5 +446,5 @@
 	if (!(source->peak->type == PM_PEAK_SUSPECT_SATURATION)) {
 	    // measure basic source moments (no S/N clipping on input pixels)
-	    status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
+	    status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, MIN_KRON_RADIUS, maskVal);
 	} else { 
 	    // For saturated stars, choose a much larger box NOTE this is slightly sleazy, but
@@ -447,5 +462,5 @@
 
 	    psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
-	    status = pmSourceMoments (source, BIG_RADIUS, BIG_SIGMA, 0.0, maskVal);
+	    status = pmSourceMoments (source, BIG_RADIUS, BIG_SIGMA, 0.0, MIN_KRON_RADIUS, maskVal);
 	    source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
 	}
@@ -456,4 +471,10 @@
 	    continue;
 	}
+
+	// XXX test of masking neighbors when measureing moments (does this fail?)
+	// psEllipseMoments moments = {source->moments->Mxx, source->moments->Myy, source->moments->Mxy};
+	// psEllipseAxes axes = psEllipseMomentsToAxes(moments, 20.0);
+        // psImageMaskCircle (source->maskView, source->peak->x, source->peak->y, 3.0*axes.major, "OR", markVal);
+
 	Nmoments ++;
 
@@ -492,4 +513,5 @@
     float sigma[NSIGMA] = {1.0, 2.0, 3.0, 4.5, 6.0, 9.0, 12.0, 18.0};
     float Sout[NSIGMA];
+    float Rmin[NSIGMA];
     int   Nout[NSIGMA]; // number of stars found in clump : use this to control the number of regions measured by psphotRoughClass
 
@@ -513,5 +535,5 @@
 
             // measure basic source moments (no S/N clipping on input pixels)
-            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0, maskVal);
+            status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0, 0.0, maskVal);
         }
 
@@ -524,4 +546,6 @@
         pmPSFClump psfClump = pmSourcePSFClump (NULL, NULL, sources, PSF_SN_LIM, PSF_CLUMP_GRID_SCALE, MOMENTS_SX_MAX, MOMENTS_SY_MAX, MOMENTS_AR_MAX);
         psLogMsg ("psphot", 3, "radius %.1f, nStars: %d of %d in clump, nSigma: %5.2f, X,  Y: %f, %f (%f, %f)\n", sigma[i], psfClump.nStars, psfClump.nTotal, psfClump.nSigma, psfClump.X, psfClump.Y, sqrt(psfClump.X) / sigma[i], sqrt(psfClump.Y) / sigma[i]);
+
+	Rmin[i] = pmSourceMinKronRadius(sources, PSF_SN_LIM);
 
 #if 0
@@ -549,4 +573,5 @@
     // we are looking for sigma for which Sout = 0.65 (or some other value)
     int Nstars = 0;
+    float minKronRadius = NAN;
     float Sigma = NAN;
     float minS = Sout[0];
@@ -565,4 +590,5 @@
         Sigma = sigma[i] + (0.65 - Sout[i])*(sigma[i+1] - sigma[i])/(Sout[i+1] - Sout[i]);
 	Nstars = 0.5*(Nout[i] + Nout[i+1]);
+        minKronRadius = Rmin[i] + (0.65 - Sout[i])*(Rmin[i+1] - Rmin[i])/(Sout[i+1] - Sout[i]);
     }
     psAssert (isfinite(Sigma), "did we miss a case?");
@@ -575,6 +601,7 @@
     psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
     psMetadataAddF32(analysis, PS_LIST_TAIL, "PSF_CLUMP_NSTARS", PS_META_REPLACE, "number of stars in clump", Nstars);
-
-    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
+    psMetadataAddF32(analysis, PS_LIST_TAIL, "MOMENTS_MIN_KRON", PS_META_REPLACE, "minimum Kron Radius", minKronRadius);
+
+    psLogMsg ("psphot", 3, "using window function with sigma = %f (Min Kron Radius = %f, Nstars = %d)\n", Sigma, minKronRadius, Nstars);
     return true;
 }
Index: /branches/czw_branch/20110406/psphot/src/psphotVisual.c
===================================================================
--- /branches/czw_branch/20110406/psphot/src/psphotVisual.c	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/src/psphotVisual.c	(revision 31606)
@@ -1867,5 +1867,5 @@
 	    continue;
 	}
-	if (source->errMag > 0.1) {
+	if (source->psfMagErr > 0.1) {
 	    xLOW->data.F32[nLOW] = source->moments->Mxx;
 	    yLOW->data.F32[nLOW] = source->moments->Myy;
@@ -2591,5 +2591,5 @@
 	x->data.F32[n] = source->psfMag;
 	y->data.F32[n] = dMag;
-	dy->data.F32[n] = source->errMag;
+	dy->data.F32[n] = source->psfMagErr;
 	graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
 	graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
Index: /branches/czw_branch/20110406/psphot/test/tap_psphot_stackphot.pro
===================================================================
--- /branches/czw_branch/20110406/psphot/test/tap_psphot_stackphot.pro	(revision 31605)
+++ /branches/czw_branch/20110406/psphot/test/tap_psphot_stackphot.pro	(revision 31606)
@@ -1,4 +1,6 @@
 #!/usr/bin/env mana
 # -*-sh-*-
+
+$KAPA = kapa -noX
 
 # config for ppImage to generate chip, mask, weight
Index: /branches/czw_branch/20110406/pstamp/scripts/detectability_respond.pl
===================================================================
--- /branches/czw_branch/20110406/pstamp/scripts/detectability_respond.pl	(revision 31605)
+++ /branches/czw_branch/20110406/pstamp/scripts/detectability_respond.pl	(revision 31606)
@@ -718,5 +718,5 @@
     foreach my $fpa_id (sort {$query{$a}{ROWNUM}[0] <=> $query{$b}{ROWNUM}[0] } (keys %query)) {
 	if ($fpa_id eq 'Not_Set') {
-	    foreach my $index (@{ $query{$a}{ROWNUM} }) {
+	    foreach my $index (@{ $query{$fpa_id}{ROWNUM} }) {
 		push @{ $query{$fpa_id}{PROC_ERROR} }, 23;
 		push @{ $query{$fpa_id}{NPIX} }, -1;
@@ -732,5 +732,10 @@
 	}
 	
-	print "BADPLACE: $fpa_id\n";
+	print "BADPLACE: $fpa_id $query{$fpa_id}\n";
+	foreach my $k (keys %{ $query{$fpa_id} }) {
+	    print "$k $query{$fpa_id}{$k}\n";
+	}
+	unless (defined($query{$fpa_id}{ROWNUM})) {
+	    $
 	push @{$colData{'ROWNUM'}}, @{ $query{$fpa_id}{ROWNUM} };
 	push @{$colData{'ERROR_CODE'}}, @{ $query{$fpa_id}{PROC_ERROR} };
Index: /branches/czw_branch/20110406/pstamp/scripts/pstamp_job_run.pl
===================================================================
--- /branches/czw_branch/20110406/pstamp/scripts/pstamp_job_run.pl	(revision 31605)
+++ /branches/czw_branch/20110406/pstamp/scripts/pstamp_job_run.pl	(revision 31606)
@@ -146,9 +146,9 @@
             # user required uncensored but since stage isn't chip we can't rebuild them
             my_die("uncensored inputs not available for job $job_id", $job_id, $PSTAMP_NOT_AVAILABLE, 'stop');
-        } elsif (($options & $PSTAMP_REQUEST_UNCENSORED) and ($params->{state} eq 'update') and ($stage ne 'chip')) {
+        } elsif (($options & $PSTAMP_REQUEST_UNCENSORED) and ($params->{state} ne 'full') and ($stage ne 'chip')) {
             # we can only restore pixels for chip stage images if the data has been updated.
-            # XXX: this test is not quite good enough. If all components have been updated then the
-            # state will be 'full' But this will get us going.
-            print "Run state is update: will make stamps from destreaked $stage images.\n";
+            # the data will have been updated if the params->{state} the state when the job was queued is not 'full' (
+            # XXX: we should probably be looking explicitly at the job and checking for a dep_id
+            print "Run state was $params->{state}: will make stamps from destreaked $stage images.\n";
             # make stamps from uncensored images
             $muggle = 0;
Index: /branches/czw_branch/20110406/pstamp/scripts/pstampparse.pl
===================================================================
--- /branches/czw_branch/20110406/pstamp/scripts/pstampparse.pl	(revision 31605)
+++ /branches/czw_branch/20110406/pstamp/scripts/pstampparse.pl	(revision 31606)
@@ -754,6 +754,7 @@
     if ( $num_jobs == 0 ) {
         print STDERR "no jobs for row $rownum\n" if $verbose;
-        insertFakeJobForRow($row, 1, $PSTAMP_NO_JOBS_QUEUED);
+        insertFakeJobForRow($row, 1, $PSTAMP_NO_IMAGE_MATCH);
         $num_jobs = 1;
+	$row->{job_num} = 1;
     }
     return $num_jobs;
Index: /branches/czw_branch/20110406/pswarp/src/pswarpTransformSources.c
===================================================================
--- /branches/czw_branch/20110406/pswarp/src/pswarpTransformSources.c	(revision 31605)
+++ /branches/czw_branch/20110406/pswarp/src/pswarpTransformSources.c	(revision 31606)
@@ -101,5 +101,5 @@
         new->psfMag = source->psfMag;
         new->extMag = source->extMag;
-        new->errMag = source->errMag;
+        new->psfMagErr = source->psfMagErr;
         new->apMag = source->apMag;
         new->pixWeightNotBad = source->pixWeightNotBad;
@@ -116,5 +116,5 @@
           (isfinite(new->psfMag) ? pow(10.0, -0.4*new->psfMag) : NAN);
         new->modelPSF->dparams->data.F32[PM_PAR_I0]=
-          (isfinite(new->psfMag) ? new->errMag*pow(10.0, -0.4*new->psfMag) : NAN);
+          (isfinite(new->psfMag) ? new->psfMagErr*pow(10.0, -0.4*new->psfMag) : NAN);
 
 #if 0
