Index: trunk/Ohana/src/relphot/src/ConfigInit.c
===================================================================
--- trunk/Ohana/src/relphot/src/ConfigInit.c	(revision 34642)
+++ trunk/Ohana/src/relphot/src/ConfigInit.c	(revision 34749)
@@ -6,5 +6,4 @@
   char  *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -45,7 +44,6 @@
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
 
-  sprintf (ImageCat, "%s/Images.dat", CATDIR);
+  snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", CATDIR);
 
   if (!ScanConfig (config, "SKY_DEPTH",         "%d",  0, &SKY_DEPTH)) {
@@ -69,6 +67,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: trunk/Ohana/src/relphot/src/StarOps.c
===================================================================
--- trunk/Ohana/src/relphot/src/StarOps.c	(revision 34642)
+++ trunk/Ohana/src/relphot/src/StarOps.c	(revision 34749)
@@ -356,6 +356,4 @@
 
   for (j = 0; j < catalog[Nc].Naverage; j++) {
-    // XXX accumulate all secfilt values in a single pass?
-
     // option for a test print
     if (FALSE && (catalog[Nc].average[j].objID == 0x7146) && (catalog[Nc].average[j].catID == 0x49d8)) {
@@ -376,4 +374,9 @@
 
     int Nmeas = 0; // number of meas used for psfqf, psfqfperf, and stargal
+
+    int NstackGood = 0;
+    int NstackSuspect = 0;
+
+    int haveStackObject = FALSE;
 
     int Ns;
@@ -401,9 +404,7 @@
 
       float stackCenterOffsetMin = 1e9;
-      // int stackCenterIDmin = -1;
       off_t stackCenterMeasureMin = -1;
 
       float stackPrimaryOffsetMin = 1e9;
-      // int stackPrimaryIDmin = -1;
       off_t stackPrimaryMeasureMin = -1;
 
@@ -415,4 +416,7 @@
       int minUbercalDist = 1000;
     
+      int isBad = FALSE;
+      int isSuspect = FALSE;
+
       N = 0;
       m = catalog[Nc].averageT[j].measureOffset;
@@ -447,23 +451,8 @@
 	if (isnan(Msys)) SKIP_THIS_MEAS(Nsys);
 
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-
 	int myUbercalDist = getUbercalDist(m,Nc);
 	minUbercalDist = MIN(minUbercalDist, myUbercalDist);
 
 	if (isSetMrelFinal) {
-	  // Map (aplist) and Mkron (kronlist,dkronlist) are used to calculate mean mags per filter
-	  float Map = PhotAper (&catalog[Nc].measure[m]);
-	  aplist[N] = Map - Mcal - Mmos - Mgrid;
-
-	  float Mkron = PhotKron (&catalog[Nc].measure[m]);
-	  kronlist[N] = Mkron - Mcal - Mmos - Mgrid;
-	  dkronlist[N] = catalog[Nc].measure[m].dMkron;
-
-	  // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters)
-	  psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
-	  psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQF;
-	  stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
-
 	  // special options for PS1 data
 	  if ((catalog[Nc].measure[m].photcode >= 10000) && (catalog[Nc].measure[m].photcode <= 10500)) {
@@ -484,8 +473,9 @@
 	    havePS1 = TRUE;
 	  }
+
 	  // gpc1 stack data
 	  if ((catalog[Nc].measure[m].photcode >= 11000) && (catalog[Nc].measure[m].photcode <= 11400)) {
-	    // if (pass < 2) continue;
 	    haveStack = TRUE;
+	    haveStackObject = TRUE;
 
 	    unsigned int stackImageID;
@@ -509,4 +499,21 @@
 	      stackCenterMeasureMin = m;
 	    }
+
+	    // data quality assessment
+	    isBad |= (catalog[Nc].measure[m].photFlags & code->photomBadMask);
+	    isBad |= (catalog[Nc].measure[m].psfQF < 0.85);
+	    isBad |= isnan(catalog[Nc].measure[m].psfQF);
+	    isBad |= catalog[Nc].measure[m].dM > 0.2; // S/N < 5.0
+
+	    isSuspect |= (catalog[Nc].measure[m].photFlags & code->photomPoorMask);
+	    isSuspect |= (catalog[Nc].measure[m].psfQFperf < 0.85);
+
+	    // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters, stacks and exposures)
+	    psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
+	    psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQFperf;
+	    stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
+	    Nmeas++;
+
+	    continue; // do not include stack measurements in the per-exposure statistics
 	  }
 
@@ -523,5 +530,4 @@
 		// detections without one of these bits should only be used in PASS_1
 		SKIP_THIS_MEAS(Nbad);
-		continue;
 	      }
 	    }
@@ -557,9 +563,22 @@
 	      if (pass < 4) {
 		SKIP_THIS_MEAS(Nbad);
-		continue;
 	      }
 	      haveSynth = TRUE;
 	    }
 	  }
+
+	  // Map (aplist) and Mkron (kronlist,dkronlist) are used to calculate mean mags per filter
+	  float Map = PhotAper (&catalog[Nc].measure[m]);
+	  aplist[N] = Map - Mcal - Mmos - Mgrid;
+
+	  float Mkron = PhotKron (&catalog[Nc].measure[m]);
+	  kronlist[N] = Mkron - Mcal - Mmos - Mgrid;
+	  dkronlist[N] = catalog[Nc].measure[m].dMkron;
+
+	  // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters, stacks and exposures)
+	  psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
+	  psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQFperf;
+	  stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
+	  Nmeas++;
 	}
 
@@ -572,4 +591,5 @@
 	dlist[N] = MAX (hypot(catalog[Nc].measureT[m].dM, code->photomErrSys), MIN_ERROR);
 	wlist[N] = 1.0;
+	list[N]  = Msys - Mcal - Mmos - Mgrid;
 
 	// up-weight the ubercal values (or convergence can take a long time...)
@@ -588,5 +608,4 @@
 	}
 	N++;
-	Nmeas++;
       }
 
@@ -595,4 +614,13 @@
       if (haveStack && (N > 1)) {
 	// fprintf (stderr, "multiple stack values for %10.6f %10.6f\n", catalog[Nc].averageT[j].R, catalog[Nc].averageT[j].D);
+      }
+
+      if (haveStack) {
+	if (!isSuspect && !isBad) {
+	  NstackGood ++;
+	}
+	if (isSuspect && !isBad) {
+	  NstackSuspect ++;
+	}
       }
 
@@ -764,4 +792,12 @@
       }
 
+      if (NstackGood >= 2) {
+	catalog[Nc].average[j].flags |= ID_OBJ_GOOD_STACK;
+      } else if (NstackGood + NstackSuspect >= 2) {
+	catalog[Nc].average[j].flags |= ID_OBJ_SUSPECT_STACK;
+      } else if (haveStackObject) {
+	catalog[Nc].average[j].flags |= ID_OBJ_BAD_STACK;
+      }
+
       // use NAN values for catalog[Nc].average[j].psfQF as signal
       if (!isfinite(catalog[Nc].average[j].psfQF)) {
Index: trunk/Ohana/src/relphot/src/setMrelFinal.c
===================================================================
--- trunk/Ohana/src/relphot/src/setMrelFinal.c	(revision 34642)
+++ trunk/Ohana/src/relphot/src/setMrelFinal.c	(revision 34749)
@@ -40,15 +40,5 @@
       for (i = 0; i < catalog[0].Naverage; i++) {
 	off_t N = Nsecfilt*i+Nsec;
-	catalog[0].secfilt[N].M      = NAN;
-	catalog[0].secfilt[N].Map    = NAN;
-	catalog[0].secfilt[N].dM     = NAN;
-	catalog[0].secfilt[N].Mstdev = NAN_S_SHORT;
-	catalog[0].secfilt[N].Xm     = NAN;
-	catalog[0].secfilt[N].M_20   = NAN_S_SHORT;
-	catalog[0].secfilt[N].M_80   = NAN_S_SHORT;
-	catalog[0].secfilt[N].Ncode  = 0;
-	catalog[0].secfilt[N].Nused  = 0;
-	catalog[0].secfilt[N].flags  = 0; // XXX there are no *astrometry* bits in secfilt.flags
-	catalog[0].secfilt[N].ubercalDist = 1000;
+	dvo_secfilt_init (&catalog[0].secfilt[N]);
 
 	off_t m = catalog[0].average[i].measureOffset;
@@ -247,5 +237,5 @@
 	}
 	
-	// PASS 2 : accept stack measurements
+	// PASS 2 : (no additional cut)
 
 	// PASS 1 : accept poor measurements as well (eg, POOR FIT, etc)
