Index: /trunk/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- /trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 35765)
@@ -24,6 +24,10 @@
 char  *HOSTDIR;
 
+int    PARALLEL_INPUT;
+
 int    VERBOSE;
 int    VERIFY;
+int    VERIFY_CATALOG_ONLY;
+int    IMAGES_ONLY;
 char   CATDIR[256];
 char   GSCFILE[256];
@@ -36,4 +40,5 @@
 char  *ALTERNATE_PHOTCODE_FILE;
 int    REPLACE_BY_PHOTCODE;
+int    FORCE_MERGE;
 
 char *SINGLE_CPT;
Index: /trunk/Ohana/src/dvomerge/src/args.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/args.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/args.c	(revision 35765)
@@ -15,4 +15,5 @@
   /* verify merge status of output tables, but do not modify */
   VERIFY = FALSE;
+  VERIFY_CATALOG_ONLY = FALSE;
   if ((N = get_argument (*argc, argv, "-verify"))) {
     VERIFY = TRUE;
@@ -21,4 +22,16 @@
   if ((N = get_argument (*argc, argv, "-check-only"))) {
     VERIFY = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-verify-catalogs"))) {
+    VERIFY = TRUE;
+    VERIFY_CATALOG_ONLY = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  /* extra error messages */
+  IMAGES_ONLY = FALSE;
+  if ((N = get_argument (*argc, argv, "-images-only"))) {
+    IMAGES_ONLY = TRUE;
     remove_argument (N, argc, argv);
   }
@@ -28,4 +41,11 @@
     remove_argument (N, argc, argv);
     ALTERNATE_PHOTCODE_FILE = strcreate(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  // merge even if header claims db has already been merged 
+  FORCE_MERGE = FALSE;
+  if ((N = get_argument (*argc, argv, "-force-merge"))) {
+    FORCE_MERGE = TRUE;
     remove_argument (N, argc, argv);
   }
@@ -63,4 +83,12 @@
   }
 
+  // is the input database a parallel db?
+  PARALLEL_INPUT = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-input"))) {
+    PARALLEL_INPUT = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  // is the output database a parallel db?
   PARALLEL = FALSE;
   if ((N = get_argument (*argc, argv, "-parallel"))) {
@@ -102,4 +130,12 @@
   PARALLEL_MANUAL = FALSE;
   PARALLEL_SERIAL = FALSE;
+  IMAGES_ONLY = FALSE;
+
+  // is the input database a parallel db?
+  PARALLEL_INPUT = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-input"))) {
+    PARALLEL_INPUT = TRUE;
+    remove_argument (N, argc, argv);
+  }
 
   HOST_ID = 0;
@@ -134,4 +170,16 @@
   if ((N = get_argument (*argc, argv, "-check-only"))) {
     VERIFY = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-verify-catalogs"))) {
+    VERIFY = TRUE;
+    VERIFY_CATALOG_ONLY = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  // merge even if header claims db has already been merged 
+  FORCE_MERGE = FALSE;
+  if ((N = get_argument (*argc, argv, "-force-merge"))) {
+    FORCE_MERGE = TRUE;
     remove_argument (N, argc, argv);
   }
@@ -227,4 +275,5 @@
   } 
 
+  // is the output database a parallel db?
   PARALLEL = FALSE;
   if ((N = get_argument (*argc, argv, "-parallel"))) {
Index: /trunk/Ohana/src/dvomerge/src/dvomerge.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomerge.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomerge.c	(revision 35765)
@@ -14,4 +14,8 @@
 	exit (3);
       }
+      if (IMAGES_ONLY) {
+	fprintf (stderr, "ERROR : dvomerge (input1) and (input2) into (output) : not compatible with '-images-only'\n");
+	exit (5);
+      }
       dvomergeCreate (argc, argv);
     } else {
@@ -19,4 +23,8 @@
 	fprintf (stderr, "WARNING / ERROR : dvomerge (input) into (output) from (list) : VERIFY mode not implemented\n");
 	exit (3);
+      }
+      if (IMAGES_ONLY) {
+	fprintf (stderr, "ERROR : dvomerge (input) input (output) from (list) : not compatible with '-images-only'\n");
+	exit (5);
       }
       dvomergeFromList (argc, argv);
Index: /trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 35765)
@@ -87,4 +87,6 @@
   int    status;
 
+  if (VERIFY && VERIFY_CATALOG_ONLY) return TRUE;
+
   /*** load input1/Images.dat ***/
   sprintf (ImageCat, "%s/Images.dat", input);
Index: /trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 35765)
@@ -22,4 +22,8 @@
     if (strcasecmp (argv[4], "continue")) dvomerge_usage();
     CONTINUE = TRUE;
+    if (IMAGES_ONLY) {
+      fprintf (stderr, "-images-only is not compatible with the 'continue' option\n");
+      exit (5);
+    }
   }
   if (VERIFY) CONTINUE = TRUE;
@@ -79,4 +83,5 @@
   } else {
     dvomergeImagesUpdate (&IDmap, input, output);
+    if (IMAGES_ONLY) exit (0);
   }
 
Index: /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 35765)
@@ -19,4 +19,21 @@
     int status = dvomergeUpdate_parallel (input, output, outsky, IDmap);
     return status;
+  }
+
+  // load the list of hosts
+  HostTable *table_input = NULL;
+  if (PARALLEL_INPUT) {
+    table_input = HostTableLoad (input, inlist->hosts);
+    if (!table_input) {
+      fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", inlist->hosts, input);
+      exit (1);
+    }    
+
+    // ensure we have absolute paths for hostdirs
+    for (i = 0; i < table_input->Nhosts; i++) {
+      char *tmppath = abspath (table_input->hosts[i].pathname, DVO_MAX_PATH);
+      free (table_input->hosts[i].pathname);
+      table_input->hosts[i].pathname = tmppath;
+    }
   }
 
@@ -25,4 +42,19 @@
     if (!inlist[0].regions[i][0].table) continue;
     if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
+
+    // in a parallel context, we need to re-map the input filename
+    char *filename_input = strcreate (inlist[0].filename[i]);
+    if (PARALLEL_INPUT) {
+
+      int hostID_input = inlist[0].regions[i]->hostID;
+      int table_index = table_input->index[hostID_input];
+      char *hostdir_input = table_input->hosts[table_index].pathname;
+
+      // set the parameters which guide catalog open/load/create
+      char hostfile_input[DVO_MAX_PATH];
+      snprintf (hostfile_input, DVO_MAX_PATH, "%s/%s.cpt", hostdir_input, inlist[0].regions[i]->name);
+      free (filename_input);
+      filename_input = strcreate (hostfile_input);
+    }
 
     // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
@@ -45,13 +77,15 @@
       OutputStatusFree (outstat, outlist->Nregions);
       SkyListFree (outlist); 
+      free (filename_input);
       continue; 
     }
 
     // get stats for history check, skip input catalog if file not found (NULL inStats)
-    dmhObjectStats *inStats = dmhObjectStatsRead (inlist[0].filename[i]);
+    dmhObjectStats *inStats = dmhObjectStatsRead (filename_input);
     if (!inStats) {
-      if (VERBOSE) fprintf (stderr, "skipping %s, empty \n", inlist[0].filename[i]);
-      OutputStatusFree (outstat, outlist->Nregions);
-      SkyListFree (outlist); 
+      if (VERBOSE) fprintf (stderr, "skipping %s, empty \n", filename_input);
+      OutputStatusFree (outstat, outlist->Nregions);
+      SkyListFree (outlist); 
+      free (filename_input);
       continue;
     }
@@ -75,18 +109,23 @@
       missed = (missed || outstat[j].missed);
     }
-    if (!missed) {
-      if (VERBOSE || VERIFY) fprintf (stderr, "skipping %s, already merged\n", inlist[0].filename[i]);
+    if (!FORCE_MERGE && !missed) {
+      if (VERBOSE || VERIFY) fprintf (stderr, "skipping %s, already merged\n", filename_input);
       OutputStatusFree (outstat, outlist->Nregions);
       dmhObjectStatsFree (inStats);
       SkyListFree (outlist); 
+      free (filename_input);
       continue;
     }
     if (VERIFY) { 
-      fprintf (stderr, "%s NOT merged\n", inlist[0].filename[i]);
+      fprintf (stderr, "%s NOT merged\n", filename_input);
+      OutputStatusFree (outstat, outlist->Nregions);
+      dmhObjectStatsFree (inStats);
+      SkyListFree (outlist); 
+      free (filename_input);
       continue;
     }
 
     // read the input catalog
-    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r", NsecfiltInput);
+    LoadCatalog (&incatalog, &inlist[0].regions[i][0], filename_input, "r", NsecfiltInput);
 
     // skip empty input catalogs
@@ -97,4 +136,5 @@
 	dmhObjectStatsFree (inStats);
 	SkyListFree (outlist); 
+	free (filename_input);
 	continue;
     }
@@ -106,5 +146,5 @@
 
       // skip if we have already done the merge
-      if (!outstat[j].missed) continue; 
+      if (!FORCE_MERGE && !outstat[j].missed) continue; 
 
       if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
@@ -121,5 +161,7 @@
       outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
 
-      dmhObjectAdd (outstat[j].history, &outcatalog.header, inStats);
+      if (outstat[i].missed) {
+	dmhObjectAdd (outstat[j].history, &outcatalog.header, inStats);
+      }
 
       if (!dvo_catalog_backup (&outcatalog, TRUE)) {
@@ -150,4 +192,5 @@
     dmhObjectStatsFree (inStats);
 
+    free (filename_input);
     dvo_catalog_unlock (&incatalog);
     dvo_catalog_free (&incatalog);
@@ -167,8 +210,10 @@
   snprintf (IDmapFilename, DVO_MAX_PATH, "%s/IDmap.fits", absoutput);
 
-  // save IDmap information
-  if (!IDmapSave (IDmapFilename, IDmap)) {
-    fprintf (stderr, "ERROR: failure to save the image ID map\n");
-    exit (1);
+  if (!VERIFY_CATALOG_ONLY) {
+    // save IDmap information
+    if (!IDmapSave (IDmapFilename, IDmap)) {
+      fprintf (stderr, "ERROR: failure to save the image ID map\n");
+      exit (1);
+    }
   }
 
@@ -196,7 +241,10 @@
 
     char tmpline[DVO_MAX_PATH];
-    if (VERBOSE)             { snprintf (tmpline, DVO_MAX_PATH, "%s -v",       command); strcpy (command, tmpline); }
-    if (VERIFY)              { snprintf (tmpline, DVO_MAX_PATH, "%s -verify",  command); strcpy (command, tmpline); }
-    if (REPLACE_BY_PHOTCODE) { snprintf (tmpline, DVO_MAX_PATH, "%s -replace", command); strcpy (command, tmpline); }
+    if (VERBOSE)             { snprintf (tmpline, DVO_MAX_PATH, "%s -v",               command); strcpy (command, tmpline); }
+    if (VERIFY)              { snprintf (tmpline, DVO_MAX_PATH, "%s -verify",          command); strcpy (command, tmpline); }
+    if (VERIFY_CATALOG_ONLY) { snprintf (tmpline, DVO_MAX_PATH, "%s -verify-catalogs", command); strcpy (command, tmpline); }
+    if (REPLACE_BY_PHOTCODE) { snprintf (tmpline, DVO_MAX_PATH, "%s -replace",         command); strcpy (command, tmpline); }
+    if (PARALLEL_INPUT)      { snprintf (tmpline, DVO_MAX_PATH, "%s -parallel-input",  command); strcpy (command, tmpline); }
+    if (FORCE_MERGE)         { snprintf (tmpline, DVO_MAX_PATH, "%s -force-merge",     command); strcpy (command, tmpline); }
 
     fprintf (stderr, "command: %s\n", command);
Index: /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c	(revision 35765)
@@ -124,4 +124,8 @@
     if (strcasecmp (argv[4], "continue")) dvomerge_usage();
     CONTINUE = TRUE;
+    if (IMAGES_ONLY) {
+      fprintf (stderr, "-images-only is not compatible with the 'continue' option\n");
+      exit (5);
+    }
   }
 
@@ -183,4 +187,5 @@
   } else {
     dvomergeImagesUpdate (&IDmap, input, output);
+    if (IMAGES_ONLY) exit (0);
   }
 
Index: /trunk/Ohana/src/dvomerge/src/dvomerge_client.c
===================================================================
--- /trunk/Ohana/src/dvomerge/src/dvomerge_client.c	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/src/dvomerge_client.c	(revision 35765)
@@ -55,9 +55,11 @@
   snprintf (IDmapFilename, DVO_MAX_PATH, "%s/IDmap.fits", absoutput);
 
-  // save IDmap information
-  IDmap = IDmapLoad (IDmapFilename);
-  if (!IDmap) {
-    fprintf (stderr, "ERROR: failure to save the image ID map\n");
-    exit (1);
+  if (!VERIFY_CATALOG_ONLY) {
+    // save IDmap information
+    IDmap = IDmapLoad (IDmapFilename);
+    if (!IDmap) {
+      fprintf (stderr, "ERROR: failure to save the image ID map\n");
+      exit (1);
+    }
   }
 
Index: /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-input.sh
===================================================================
--- /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-input.sh	(revision 35765)
+++ /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-input.sh	(revision 35765)
@@ -0,0 +1,10 @@
+#!/bin/csh -f
+
+ rm -rf catdir.merge catdir.grizy.output
+ rsync --exclude=.svn -auv catdir.2mass/ catdir.merge/
+ rsync --exclude=.svn -auv catdir.grizy/ catdir.grizy.output/
+ cp HostTable.dat catdir.merge/
+ dvodist -out catdir.merge
+ rm -rf catdir.merge/n0000 catdir.merge/n0730
+ dvomerge -parallel-input catdir.merge into catdir.grizy.output/
+ dvomerge -verify -parallel-input catdir.merge into catdir.grizy.output/
Index: /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-parallel.sh
===================================================================
--- /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-parallel.sh	(revision 35765)
+++ /trunk/Ohana/src/dvomerge/test/dvomerge.parallel-parallel.sh	(revision 35765)
@@ -0,0 +1,24 @@
+#!/bin/csh -f
+
+ rm -rf catdir.merge catdir.grizy.output
+ rsync --exclude=.svn -auv catdir.2mass/ catdir.2mass.input/
+ rsync --exclude=.svn -auv catdir.grizy/ catdir.grizy.output/
+
+ set rootdir = `pwd`
+ sed "s|catdir.merge|$rootdir/catdir.2mass.input|"  < HostTable.dat > catdir.2mass.input/HostTable.dat
+ sed s/catdir.merge/catdir.grizy.output/ < HostTable.dat > catdir.grizy.output/HostTable.dat
+
+ dvodist -out catdir.2mass.input
+ dvodist -out catdir.grizy.output
+
+ rm -rf catdir.2mass.input/n???? 
+ rm -rf catdir.grizy.output/n????
+
+ dvomerge -parallel-input -parallel catdir.2mass.input into catdir.grizy.output -region 0.01 4.99 0.01 2.49 -v
+ # dvomerge -parallel-input -parallel catdir.2mass.input into catdir.grizy.output -verify
+
+ ## XXX note : this test fails because there are multiple input
+ ## catdirs for a given output catdir AND the sizes and timestamps of
+ ## the cpt files match (size matches because of the 2880 block size;
+ ## time matches because they are all touched in ~1 sec).
+
Index: /trunk/Ohana/src/dvomerge/test/dvomerge.parallel.sh
===================================================================
--- /trunk/Ohana/src/dvomerge/test/dvomerge.parallel.sh	(revision 35764)
+++ /trunk/Ohana/src/dvomerge/test/dvomerge.parallel.sh	(revision 35765)
@@ -1,7 +1,10 @@
 #!/bin/csh -f
 
- rm -rf catdir.merge
- rsync -auv catdir.2mass/ catdir.merge/
+ rm -rf catdir.merge catdir.merge.p?
+ rsync --exclude=.svn -auv catdir.2mass/ catdir.merge/
  cp HostTable.dat catdir.merge/
  dvodist -out catdir.merge
+ rm -rf catdir.merge/n????
+
  dvomerge -parallel catdir.grizy into catdir.merge
+ dvomerge -parallel catdir.grizy into catdir.merge -verify
