Index: /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify.c	(revision 34302)
+++ /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify.c	(revision 34303)
@@ -42,4 +42,8 @@
   }
 
+  if (CHECK_IMAGE_ID) {
+    LoadImageIDs (CATDIR);
+  }
+
   // load the sky table for the existing database
   sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
Index: /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_args.c
===================================================================
--- /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 34302)
+++ /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 34303)
@@ -53,4 +53,10 @@
   if ((N = get_argument (*argc, argv, "-skip-toplevel"))) {
     CHECK_TOPLEVEL = FALSE;
+    remove_argument (N, argc, argv);
+  }
+
+  CHECK_IMAGE_ID = TRUE;
+  if ((N = get_argument (*argc, argv, "-skip-image-ids"))) {
+    CHECK_IMAGE_ID = FALSE;
     remove_argument (N, argc, argv);
   }
Index: /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 34302)
+++ /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 34303)
@@ -100,7 +100,8 @@
 
     char tmpline[DVO_MAX_PATH];
-    if (VERBOSE)      { snprintf (tmpline, DVO_MAX_PATH, "%s -v", command); strcpy (command, tmpline); }
-    if (CHECKSORTED)  { snprintf (tmpline, DVO_MAX_PATH, "%s -s", command); strcpy (command, tmpline); }
-    if (LIST_MISSING) { snprintf (tmpline, DVO_MAX_PATH, "%s -list-missing", command); strcpy (command, tmpline); }
+    if (VERBOSE)         { snprintf (tmpline, DVO_MAX_PATH, "%s -v", command); strcpy (command, tmpline); }
+    if (CHECKSORTED)     { snprintf (tmpline, DVO_MAX_PATH, "%s -s", command); strcpy (command, tmpline); }
+    if (!CHECK_IMAGE_ID) { snprintf (tmpline, DVO_MAX_PATH, "%s -skip-image-ids", command); strcpy (command, tmpline); }
+    if (LIST_MISSING)    { snprintf (tmpline, DVO_MAX_PATH, "%s -list-missing", command); strcpy (command, tmpline); }
 
     fprintf (stderr, "command: %s\n", command);
Index: /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_client.c
===================================================================
--- /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_client.c	(revision 34302)
+++ /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_client.c	(revision 34303)
@@ -19,4 +19,10 @@
   skylist = SkyListByPatch (sky, -1, &UserPatch);
   
+  if (CHECK_IMAGE_ID) {
+    // XXX in client mode, we should be reading a reduced table generated by the calling
+    // serial program
+    LoadImageIDs (CATDIR);
+  }
+
   dvoverify_catalogs (skylist, &Nbad);
 
Index: /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_utils.c
===================================================================
--- /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 34302)
+++ /branches/eam_branches/ipp-20120805/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 34303)
@@ -49,4 +49,6 @@
 
 // is this file a consistent FITS file?
+// note that VerifyTableFile only has to read the headers,
+// not the data blocks (it uses stat for sizes)
 int VerifyTableFile (char *filename) {
 
@@ -194,5 +196,5 @@
   // \sum average[].Nmeasure = Nmeasure
 
-  // if the table is NOT SORTED, we have a subset of checks we can make
+  // if the table is NOT SORTED, do we have a subset of checks we can make?
   if (!catalog.sorted) {
     fprintf (stderr, "!");
@@ -231,4 +233,6 @@
   }
 
+  // if we have a problem with Nmeasure and/or measureOffset values, we
+  // cannot do any further check -- we risk segfaults
   if (!status) {
     dvo_catalog_unlock (&catalog);
@@ -263,12 +267,12 @@
   }
 
-//  for (i = 0; i < catalog.Naverage; i++) {
-//    m = catalog.average[i].measureOffset;
-//    for (j = 0; i < catalog.Nmeasure; i++) {
-//      objIDsOK &= (catalog.average[i].objID == catalog.measure[m+j].objID);
-//      catIDsOK &= (catalog.average[i].catID == catalog.measure[m+j].catID);
-//      averefOK &= (catalog.measure[m+j].averef = i);
-//    }
-//  }
+  // check the image ID here?
+  if (CHECK_IMAGE_ID) {
+    int Nfail = CheckImageID (&catalog);
+    if (Nfail > 0) {
+      fprintf (stderr, "ERROR: catalog %s has invalid %d unmatched image IDs\n", catalog.filename, Nfail);
+      status = FALSE;
+    }
+  }
 
   dvo_catalog_unlock (&catalog);
@@ -278,6 +282,95 @@
 }
 
-// gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
-// gfits_scan(&cpmHeaderTBL, "NAXIS2", "%d", 1, &Nrows);
-    
+static int maxID = 0;
+static int *IDlist = NULL;
+
+// check that every measure->imageID (if set) matches an existing 
+// image->ID.  return the number of failures.
+int CheckImageID (Catalog *catalog) {
+
+  off_t i, j, m, id;
+  int Nfail = 0;
+
+  for (i = 0; i < catalog[0].Naverage; i++) {
+    m = catalog[0].average[i].measureOffset;
+    for (j = 0; j < catalog[0].average[i].Nmeasure; j++) {
+      id = catalog[0].measure[m+j].imageID;
+      if (id > maxID) {
+	Nfail ++;
+	continue;
+	// is this sufficient to catch IDs set without an image table?
+      }
+      if (IDlist) {
+	if (IDlist[id] < 0) {
+	  Nfail ++;
+	  continue;
+	}
+      } else {
+	if (id > 0) {
+	  Nfail ++;
+	  continue;
+	}
+      }
+    }
+  }
+  return Nfail;
+}
+
+int LoadImageIDs (char *catdir) {
+
+  int status;
+  off_t Nimages, i;
+  Image *images;
+  FITS_DB inDB;
+
+  char ImageCat[DVO_MAX_PATH];
+  snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", catdir);
+
+  // load the iage database table
+  status = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_SOFT);  // shorter timeout?
+  if (!status) {
+    fprintf (stderr, "ERROR: failure to lock image catalog %s", inDB.filename);
+    exit (3);
+  }
+
+  // load the image table 
+  if (inDB.dbstate == LCK_EMPTY) {
+    dvo_image_unlock (&inDB); // unlock input
+    // this is not an error: we can have no image table for, eg, 2MASS only db
+    return TRUE;
+  }
+  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
+    fprintf (stderr, "can't read input image catalog %s", inDB.filename);
+    exit (4);
+  }
+
+  images = gfits_table_get_Image (&inDB.ftable, &Nimages, &inDB.swapped);
+  if (!images) {
+    fprintf (stderr, "ERROR: failed to read images from src\n");
+    exit (2);
+  }
+
+  // generate a lookup table for the images
   
+  // first, find the max imageID
+  for (i = 0; i < Nimages; i++) {
+    maxID = MAX(maxID, images[i].imageID);
+  }
+
+  ALLOCATE (IDlist, int, maxID + 1);
+  for (i = 0; i < maxID + 1; i++) {
+    IDlist[i] = -1;
+  }
+
+  for (i = 0; i < Nimages; i++) {
+    int id = images[i].imageID;
+    IDlist[id] = i;
+  }
+
+  // free image table here?
+  // (in the future, I'll have to do the image table read in segments
+  // it is just getting to be too large...)
+  dvo_image_unlock (&inDB); // unlock input
+
+  return TRUE;
+}
