Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/Makefile
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/Makefile	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/Makefile	(revision 33834)
@@ -1,5 +1,5 @@
 default: all
 help:
-	@echo "make options: dvomerge (default)"
+	@echo "make options: dvomerge dvomerge_client dvoconvert (default)"
 
 include ../../Makefile.System
@@ -17,8 +17,9 @@
 FULL_LDFLAGS  = -lkapa -ldvo -lFITS -lohana $(BASE_LDFLAGS)
 
-dvomerge     : $(BIN)/dvomerge.$(ARCH)
-dvomerge     : $(BIN)/dvoconvert.$(ARCH)
+dvomerge        : $(BIN)/dvomerge.$(ARCH)
+dvomerge_client : $(BIN)/dvomerge_client.$(ARCH)
+dvoconvert      : $(BIN)/dvoconvert.$(ARCH)
 
-all: dvomerge dvoconvert dvosecfilt
+all: dvomerge dvomerge_client dvoconvert dvosecfilt
 
 #  $(SRC)/dvomergeContinue.$(ARCH).o
@@ -28,4 +29,5 @@
 $(SRC)/dvomergeUpdate.$(ARCH).o \
 $(SRC)/dvomergeCreate.$(ARCH).o \
+$(SRC)/dvomergeUpdate_catalogs.$(ARCH).o \
 $(SRC)/dvomergeUpdate_threaded.$(ARCH).o \
 $(SRC)/dvomergeFromList.$(ARCH).o \
@@ -47,4 +49,25 @@
 
 $(BIN)/dvomerge.$(ARCH) : $(DVOMERGE)
+
+DVOMERGE_CLIENT = \
+$(SRC)/dvomerge_client.$(ARCH).o \
+$(SRC)/dvomergeUpdate_catalogs.$(ARCH).o \
+$(SRC)/dvomergeImageIDs.$(ARCH).o \
+$(SRC)/dvo_image_merge_dbs.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/help.$(ARCH).o \
+$(SRC)/args.$(ARCH).o \
+$(SRC)/psps_ids.$(ARCH).o \
+$(SRC)/SkyTablePopulatedRange.$(ARCH).o \
+$(SRC)/LoadCatalog.$(ARCH).o \
+$(SRC)/build_links.$(ARCH).o \
+$(SRC)/merge_catalogs_new.$(ARCH).o \
+$(SRC)/merge_catalogs_old.$(ARCH).o
+
+$(DVOMERGE_CLIENT) : $(INC)/dvomerge.h
+
+$(BIN)/dvomerge_client.$(ARCH) : $(DVOMERGE_CLIENT)
 
 DVOCONVERT = \
@@ -99,5 +122,5 @@
 $(BIN)/dvoverify.$(ARCH) : $(DVOVERIFY)
 
-INSTALL = dvomerge dvoconvert dvosecfilt dvorepair dvoverify
+INSTALL = dvomerge dvomerge_client dvoconvert dvosecfilt dvorepair dvoverify
 
 # dependancy rules for binary code #########################
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/doc/parallel.txt
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/doc/parallel.txt	(revision 33834)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/doc/parallel.txt	(revision 33834)
@@ -0,0 +1,8 @@
+
+dvomergeUpdate parallel version:
+
+ * master should update photcode table & image table
+ * master should call remote clients to update their catalog tables
+ * write out a temporary IDmap for the remote clients?
+ * put the inlist loop into a function which can be called by the client or the master
+ 
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/include/dvomerge.h	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/include/dvomerge.h	(revision 33834)
@@ -16,4 +16,14 @@
 # include <arpa/inet.h>
 # include <glob.h>
+
+# define MAX_PATH_LENGTH 1024
+
+int    PARALLEL;
+int    PARALLEL_MANUAL;
+int    PARALLEL_SERIAL;
+
+int    HOST_ID;
+char  *HOSTDIR;
+
 
 int    VERBOSE;
@@ -51,4 +61,8 @@
 void 	   dvomerge_help          PROTO((int argc, char **argv));
 int  	   dvomerge_args 	  PROTO((int *argc, char **argv));
+
+void       dvomerge_client_usage  PROTO((void));
+void 	   dvomerge_client_help   PROTO((int argc, char **argv));
+int  	   dvomerge_client_args   PROTO((int *argc, char **argv));
 
 void       dvoconvert_usage       PROTO((void));
@@ -110,2 +124,3 @@
 int        dvomergeFromList       PROTO((int argc, char **argv));
 int 	   dvomergeUpdate_threaded PROTO((int argc, char **argv));
+int        dvomergeUpdate_catalogs PROTO((char *input, char *output, SkyTable *outsky, SkyList *inlist, int NsecfiltInput, int NsecfiltOutput, IDmapType IDmap, int *secfiltMap));
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/args.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/args.c	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/args.c	(revision 33834)
@@ -43,5 +43,95 @@
   }
 
+  // XXX for the moment, make this selection manual.  it needs to be automatic 
+  // based on the state of the SkyTable
+  PARALLEL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel"))) {
+    PARALLEL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  // this is a test mode : rather than launching the remote jobs and waiting for completion,
+  // relphot will simply list the remote command and wait for the user to signal completion
+  PARALLEL_MANUAL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-manual"))) {
+    PARALLEL = TRUE; // -parallel-manual implies -parallel
+    PARALLEL_MANUAL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  // this is a test mode : rather than launching the relphot_client jobs remotely, they are 
+  // run in serial via 'system'
+  PARALLEL_SERIAL = FALSE;
+  if ((N = get_argument (*argc, argv, "-parallel-serial"))) {
+    if (PARALLEL_MANUAL) {
+      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
+      exit (1);
+    }
+    PARALLEL = TRUE; // -parallel-serial implies -parallel
+    PARALLEL_SERIAL = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
   if ((*argc < 4) || (*argc > 6)) dvomerge_usage();
+  return TRUE;
+}
+
+/*** check for command line options ***/
+int dvomerge_client_args (int *argc, char **argv) {
+  
+  int N;
+
+  // by definition, the client is not parallel 
+  PARALLEL = FALSE;
+  PARALLEL_MANUAL = FALSE;
+  PARALLEL_SERIAL = FALSE;
+
+  HOST_ID = 0;
+  if ((N = get_argument (*argc, argv, "-hostID"))) {
+    remove_argument (N, argc, argv);
+    HOST_ID = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (!HOST_ID) dvomerge_client_usage();
+
+  HOSTDIR = NULL;
+  if ((N = get_argument (*argc, argv, "-hostdir"))) {
+    remove_argument (N, argc, argv);
+    HOSTDIR = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (!HOSTDIR) dvomerge_client_usage();
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (*argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  NTHREADS = 0;
+  if ((N = get_argument (*argc, argv, "-threads"))) {
+    remove_argument (N, argc, argv);
+    NTHREADS = MAX(0, atoi(argv[N]));
+    remove_argument (N, argc, argv);
+  }
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (*argc, argv, "-region"))) {
+    remove_argument (N, argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  if ((*argc < 4) || (*argc > 6)) dvomerge_client_usage();
   return TRUE;
 }
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeImageIDs.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 33834)
@@ -17,4 +17,5 @@
   // load the image table 
   if (inDB.dbstate == LCK_EMPTY) {
+    dvo_image_unlock (&inDB); // unlock input
     IDmap->Nmap = 0;
     return TRUE;
@@ -68,4 +69,5 @@
   // load the image table
   if (inDB.dbstate == LCK_EMPTY) {
+    dvo_image_unlock (&inDB); // unlock input
     IDmap->Nmap = 0;
     return TRUE;
@@ -86,5 +88,5 @@
   /* load the image table */
   if (outDB.dbstate == LCK_EMPTY) {
-    Shutdown ("only use -continue for an existing, partially merged database");
+    Shutdown ("for dvomerge -continue or dvomerge_client, the output database must exist");
   } 
   if (!dvo_image_load (&outDB, VERBOSE, TRUE)) {
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 33834)
@@ -4,8 +4,6 @@
 
   int CONTINUE;
-  off_t i, j;
   SkyTable *outsky, *insky;
-  SkyList *outlist, *inlist;
-  Catalog incatalog, outcatalog;
+  SkyList *inlist;
   char filename[256], *input, *output;
   IDmapType IDmap;
@@ -107,54 +105,5 @@
   SetPhotcodeTable(NULL);
 
-  // loop over the populated input regions
-  for (i = 0; i < inlist[0].Nregions; i++) {
-    if (!inlist[0].regions[i][0].table) continue;
-    if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
-
-    // load / create output catalog (if catalog does not exist, it will be created)
-    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r", NsecfiltInput);
-    // skip empty input catalogs
-    if (!incatalog.Naves_disk) {
-	dvo_catalog_unlock (&incatalog);
-	dvo_catalog_free (&incatalog);
-	continue;
-    }
-
-    // combine only tables at equal or larger depth
-      
-    // load in all of the tables from input for this region
-    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
-    // compare to a slightly reduced footprint
-    float dPos = 2.0/3600.0;
-    outlist = SkyListByBounds (outsky, inlist[0].regions[i][0].depth, inlist[0].regions[i][0].Rmin + dPos, inlist[0].regions[i][0].Rmax - dPos, inlist[0].regions[i][0].Dmin + dPos, inlist[0].regions[i][0].Dmax - dPos);
-    for (j = 0; j < outlist[0].Nregions; j++) {
-      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
-
-      // load input catalog
-      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w", NsecfiltOutput);
-
-      dvo_update_image_IDs (&IDmap, &incatalog);
-      merge_catalogs_old (&outsky[0].regions[j], &outcatalog, &incatalog, RADIUS, secfiltMap);
-
-      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
-
-      // if we receive a signal which would cause us to exit, wait until the full catalog is written
-      SetProtect (TRUE);
-      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
-	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
-	exit (1);
-      }
-      SetProtect (FALSE);
-
-      dvo_catalog_unlock (&outcatalog);
-      dvo_catalog_free (&outcatalog);
-
-      fprintf (stderr, "merged %s into %s\n", inlist[0].regions[i][0].name, outlist[0].regions[j][0].name);
-    }
-    SkyListFree (outlist);
-
-    dvo_catalog_unlock (&incatalog);
-    dvo_catalog_free (&incatalog);
-  }
+  dvomergeUpdate_catalogs (input, output, outsky, inlist, NsecfiltInput, NsecfiltOutput, IDmap, secfiltMap);
 
   // save the output sky table copy
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 33834)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 33834)
@@ -0,0 +1,164 @@
+# include "dvomerge.h"
+# define DEBUG 1
+
+// in parallel mode, the target database may be distributed, while the input database is
+// only on a single machine
+
+// this function only merges tables which are at equal or shallower depth compared to the
+// output tables
+
+int dvomergeUpdate_parallel (char *input, char *output, SkyTable *outsky);
+
+int dvomergeUpdate_catalogs (char *input, char *output, SkyTable *outsky, SkyList *inlist, int NsecfiltInput, int NsecfiltOutput, IDmapType IDmap, int *secfiltMap) {
+
+  off_t i, j;
+  SkyList *outlist;
+  Catalog incatalog, outcatalog;
+
+  if (PARALLEL && !HOST_ID) {
+    int status = dvomergeUpdate_parallel (input, output, outsky);
+    return status;
+  }
+
+  // loop over the populated input regions
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+    if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
+
+    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
+    // compare to a slightly reduced footprint
+    float dPos = 2.0/3600.0;
+    outlist = SkyListByBounds (outsky, -1, inlist[0].regions[i][0].Rmin + dPos, inlist[0].regions[i][0].Rmax - dPos, inlist[0].regions[i][0].Dmin + dPos, inlist[0].regions[i][0].Dmax - dPos);
+
+    // there may be more than one output region for a given input region.  are any of these output regions relevant to this machine?
+    int found = FALSE;
+    for (j = 0; !found && (j < outlist[0].Nregions); j++) {
+      found = (found || HostTableTestHost(outlist[0].regions[j], HOST_ID));
+    }
+    // skip this input table for if no output files are on this machine
+    if (!found) {
+      SkyListFree (outlist); 
+      continue; 
+    }
+
+    // load / create output catalog (if catalog does not exist, it will be created)
+    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r", NsecfiltInput);
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+	dvo_catalog_unlock (&incatalog);
+	dvo_catalog_free (&incatalog);
+	SkyListFree (outlist); 
+	continue;
+    }
+
+    // merge input into the appropriate output tables
+    for (j = 0; j < outlist[0].Nregions; j++) {
+      // skip tables for which the output files are not on this machine
+      if (!HostTableTestHost(outlist[0].regions[j], HOST_ID)) continue; 
+
+      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
+
+      // set the parameters which guide catalog open/load/create
+      char hostfile[MAX_PATH_LENGTH];
+      snprintf (hostfile, MAX_PATH_LENGTH, "%s/%s.cpt", HOSTDIR, outlist[0].regions[j]->name);
+      outcatalog.filename  = HOST_ID ? hostfile : outlist[0].filename[j];
+
+      // load input catalog
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outcatalog.filename, "w", NsecfiltOutput);
+
+      dvo_update_image_IDs (&IDmap, &incatalog);
+      merge_catalogs_old (outlist[0].regions[j], &outcatalog, &incatalog, RADIUS, secfiltMap);
+
+      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+      // if we receive a signal which would cause us to exit, wait until the full catalog is written
+      SetProtect (TRUE);
+      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
+	exit (1);
+      }
+      SetProtect (FALSE);
+
+      dvo_catalog_unlock (&outcatalog);
+      dvo_catalog_free (&outcatalog);
+
+      fprintf (stderr, "merged %s into %s\n", inlist[0].regions[i][0].name, outlist[0].regions[j][0].name);
+    }
+    SkyListFree (outlist);
+
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+  }
+  return TRUE;
+}
+
+int dvomergeUpdate_parallel (char *input, char *output, SkyTable *outsky) {
+
+  // launch the dvomergeUpdate_client jobs to the parallel hosts
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (output, outsky->hosts);
+  if (!table) {
+    fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", outsky->hosts, output);
+    exit (1);
+  }    
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    // ensure that the paths are absolute path names
+    char *tmppath = abspath (table->hosts[i].pathname, MAX_PATH_LENGTH);
+    free (table->hosts[i].pathname);
+    table->hosts[i].pathname = tmppath;
+
+    // ensure that the paths are absolute path names
+    char *absinput  = abspath (input,  MAX_PATH_LENGTH);
+    char *absoutput = abspath (output, MAX_PATH_LENGTH);
+
+    // options / arguments that can affect relastro_client -update-objects:
+    char command[MAX_PATH_LENGTH];
+    snprintf (command, MAX_PATH_LENGTH, "dvomerge_client %s into %s -hostID %d -hostdir %s -region %f %f %f %f -D ADDSTAR_RADIUS %f", 
+	      absinput, absoutput, table->hosts[i].hostID, table->hosts[i].pathname, 
+	      UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax, RADIUS
+      );
+
+    char tmpline[MAX_PATH_LENGTH];
+    if (VERBOSE)            { snprintf (tmpline, MAX_PATH_LENGTH, "%s -v",                command);            strcpy (command, tmpline); }
+
+    // XXX these do not make sense for dvomerge client, where the output is required to exist
+    // if (CATFORMAT)          { snprintf (tmpline, MAX_PATH_LENGTH, "%s -D CATFORMAT %s",   command, CATFORMAT); strcpy (command, tmpline); }
+    // if (CATMODE)            { snprintf (tmpline, MAX_PATH_LENGTH, "%s -D CATMODE %s",     command, CATMODE);   strcpy (command, tmpline); }
+    // if (SKY_DEPTH)          { snprintf (tmpline, MAX_PATH_LENGTH, "%s -D SKY_DEPTH %d",   command, SKY_DEPTH); strcpy (command, tmpline); }
+
+    fprintf (stderr, "command: %s\n", command);
+
+    if (PARALLEL_MANUAL) continue;
+
+    if (PARALLEL_SERIAL) {
+      int status = system (command);
+      if (status) {
+	fprintf (stderr, "ERROR running photdbc_client\n");
+	exit (2);
+      }
+    } else {
+      // launch the job on the remote machine (no handshake)
+      int errorInfo = 0;
+      int pid = rconnect ("ssh", table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
+      if (!pid) {
+	if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
+	exit (1);
+      }
+      table->hosts[i].pid = pid; // save for future reference
+    }
+  }
+
+  if (PARALLEL_MANUAL) {
+    fprintf (stderr, "run the photdbc_client commands above.  when these are done, hit return\n");
+    getchar();
+  }
+  if (!PARALLEL_MANUAL && !PARALLEL_SERIAL) {
+    HostTableWaitJobsGetIO (table, __FILE__, __LINE__, VERBOSE);
+  }
+
+  return TRUE;
+}      
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomerge_client.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomerge_client.c	(revision 33834)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/dvomerge_client.c	(revision 33834)
@@ -0,0 +1,79 @@
+# include "dvomerge.h"
+
+int main (int argc, char **argv) {
+
+  dvomerge_client_help (argc, argv);
+  ConfigInit (&argc, argv);
+  dvomerge_client_args (&argc, argv);
+
+  SkyTable *outsky, *insky;
+  SkyList *inlist;
+  char filename[256], *input, *output;
+  IDmapType IDmap;
+  PhotCodeData *inputPhotcodes;
+  PhotCodeData *outputPhotcodes;
+  int *secfiltMap = NULL;
+  int NsecfiltInput, NsecfiltOutput;
+
+  input  = argv[1];
+  output = argv[3];
+
+  // we need input and output photcode tables to correctly match secfilt entries
+
+  // load the input photcodes
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", input);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading input database directory %s\n", input);
+    exit (1);
+  }	
+  inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
+
+  // since we are merging the input db into the output db, the output defines the photcode
+  // table & db layout but, this requires the output to exist.  if it does not, fail
+  // (master should have created the output photcode table)
+
+  // load the output photcodes
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", output);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading output database directory %s\n", output);
+    exit (1);
+  }
+  outputPhotcodes = GetPhotcodeTable();
+  NsecfiltOutput = GetPhotcodeNsecfilt();
+
+  secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
+  if (!secfiltMap) {
+    fprintf (stderr, "failed to map input secfilt photcodes to output photcodes table\n");
+    exit (1);
+  }
+
+  dvomergeImagesGetMap (&IDmap, input, output);
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  if (!insky) {
+      Shutdown ("can't read SkyTable for %s", input);
+  }
+  SkyTableSetFilenames (insky, input, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // generate an output table populated at the desired depth
+  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  if (!outsky) {
+      Shutdown ("can't read or create SkyTable for %s", output);
+  }
+  SkyTableSetFilenames (outsky, output, "cpt");
+
+  // loop over the populatable output tables; check for data in input in the corresponding regions
+
+  SetPhotcodeTable(NULL);
+  
+   dvomergeUpdate_catalogs (input, output, outsky, inlist, NsecfiltInput, NsecfiltOutput, IDmap, secfiltMap);
+
+  exit (0);
+}
Index: /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/help.c
===================================================================
--- /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/help.c	(revision 33833)
+++ /branches/eam_branches/ipp-20120405/Ohana/src/dvomerge/src/help.c	(revision 33834)
@@ -6,4 +6,10 @@
   fprintf (stderr, "   OR: dvomerge (input) into (output) continue\n");
   fprintf (stderr, "   OR: dvomerge (input) into (output) from (list)\n");
+  fprintf (stderr, "   [-region Rmin Rmax Dmin Dmax]\n");
+  exit (2);
+}
+
+void dvomerge_client_usage (void) {
+  fprintf (stderr, "USAGE: dvomerge_client (input) into (output)\n");
   fprintf (stderr, "   [-region Rmin Rmax Dmin Dmax]\n");
   exit (2);
@@ -39,4 +45,24 @@
   fprintf (stderr, "  dvomerge (input) into (output) from (list)\n");
   fprintf (stderr, "     dvomerge list implies 'continue' : list contains, eg, n1500/1688.00.cpt (one cpt per line)\n\n");
+  fprintf (stderr, "  merge DVO databases\n");
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  fprintf (stderr, "  -region Rmin Rmax Dmin Dmax : region to merge\n\n");
+  exit (2);
+}
+
+void dvomerge_client_help (int argc, char **argv) {
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help")) goto show_help;
+  if (get_argument (argc, argv, "-h"))    goto show_help;
+  return;
+
+show_help:
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  dvomerge_client (input) into (output)\n");
   fprintf (stderr, "  merge DVO databases\n");
   fprintf (stderr, "  optional flags:\n");
