Index: /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/include/dvo.h
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/include/dvo.h	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/include/dvo.h	(revision 33244)
@@ -205,4 +205,5 @@
   char **filename;
   SkyRegion **regions;
+  char hosts[80];
 } SkyList;
 
@@ -261,5 +262,5 @@
 } PhotCodeData;
 
-// a reduced-subset structure for relphot
+// a reduced-subset structure for relphot & relastro
 typedef struct {
   double         R;
@@ -268,7 +269,8 @@
   int            measureOffset;
   uint32_t       flags;
+  int            catID;
 } AverageTiny;
 
-// a reduced-subset structure for relphot
+// a reduced-subset structure for relphot & relastro
 typedef struct {
   float          dR;
@@ -285,4 +287,5 @@
   unsigned int   imageID;
   unsigned int   dbFlags;
+  int            catID; // unsigned int?
   unsigned short photcode;
 } MeasureTiny;
Index: /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/src/skyregion_ops.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/src/skyregion_ops.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/libdvo/src/skyregion_ops.c	(revision 33244)
@@ -20,4 +20,5 @@
   list[0].Nregions = 0;
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, table[0].hosts);
 
   region = table[0].regions;
@@ -67,4 +68,5 @@
   list[0].Nregions = N;
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, table[0].hosts);
 
   region = table[0].regions;
@@ -102,4 +104,5 @@
   list[0].Nregions = N;
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, table[0].hosts);
 
   region = table[0].regions;
@@ -261,4 +264,5 @@
   ALLOCATE (list[0].filename, char *, NNEW);
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, table[0].hosts);
 
   region = table[0].regions;
@@ -326,4 +330,5 @@
   list[0].Nregions = 0;
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, inList[0].hosts);
 
   region = inList[0].regions;
@@ -403,4 +408,5 @@
   ALLOCATE (list[0].filename, char *, NNEW);
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, table[0].hosts);
 
   region = table[0].regions;
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/doc/parallel.txt
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/doc/parallel.txt	(revision 33244)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/doc/parallel.txt	(revision 33244)
@@ -0,0 +1,19 @@
+
+2012.02.10
+
+I have put together the start of parallel dvo examples.  I have
+'dvodist' to distribute the data (and pull it back), and parallel
+modifications to 'setphot'.  Here is what I need to do to relphot to
+make it work in parallel:
+
+* load_catalogs.c : a parallel version of this would spawn the remote
+  jobs in -load mode.  these should read from their owned tables,
+  collect the subset of detections (subset naturally generated by
+  bcatalog), and write the results to local temp fits files.  the main
+  program would wait until the sub programs have been finished and
+  then load in all of the subset tables.
+
+* reload_catalogs : a parallel version needs to write the subset image
+  table and then run the remote jobs.  these would read the image
+  data, and load and update their local database tables.  This is
+  nearly identical to the code in setphot / setphot_client.
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/BrightCatalog.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/BrightCatalog.c	(revision 33244)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/BrightCatalog.c	(revision 33244)
@@ -0,0 +1,482 @@
+# include "relphot.h"
+
+// relphot_client reads from the local catalogs and generates a set of bright, subset catalogs
+// we are going to save these as a single big FITS file, with only 3 extensions:
+
+// measure, average, secfilt.  these only need to contain the fields relevant to the
+// MeasureTiny, AverageTiny, and Secfilt tables, but with cat_id appended to each row so we can
+// reassign correctly on read
+
+typedef struct {
+    AverageTiny *average;
+    MeasureTiny *measure;
+    Secfilt     *secfilt;
+    off_t Naverage;
+    off_t Nmeasure;
+} BrightCatalog;
+
+# define GET_COLUMN(OUT,NAME,TYPE) \
+  TYPE *OUT = gfits_get_bintable_column_data (&theader, &ftable, NAME, type, &Nrow, &Ncol); \
+  myAssert (!strcmp(type, #TYPE), "wrong column type");
+
+// XXX double check the header extname values for each table
+// XXX make sure we free things as we can
+// XXX make sure we close files as we can
+// XXX handle free and close on error return as well
+BrightCatalog *BrightCatalogLoad(char *filename) {
+
+  int i, Ncol, Ncol2;
+  off_t Nrow;
+  char type[16];
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  BrightCatalog *catalog = NULL;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ALLOCATE (catalog, BrightCatalog, 1);
+  catalog->Naverage = 0;
+  catalog->Nmeasure = 0;
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+ 
+  // need to create and assign to flat-field correction
+  GET_COLUMN(dR,       "RA_OFF",   float);
+  GET_COLUMN(dD,       "DEC_OFF",  float);
+  GET_COLUMN(M,        "MAG_SYS",  float);
+  GET_COLUMN(Mcal,     "MAG_CAL",  float);
+  GET_COLUMN(dM,       "MAG_ERR",  float);
+  GET_COLUMN(airmass,  "AIRMASS",  float);
+  GET_COLUMN(Xccd,     "X_CCD",    float);
+  GET_COLUMN(Yccd,     "Y_CCD",    float);
+  GET_COLUMN(dt,       "EXPTIME",  float);
+  GET_COLUMN(t,        "TIME",     int);
+  GET_COLUMN(averef,   "AVE_REF",  int); // XXX signed vs unsigned?
+  GET_COLUMN(imageID,  "IMAGE_ID", int);
+  GET_COLUMN(dbFlags,  "DB_FLAGS", int);
+  GET_COLUMN(catID,    "CAT_ID",   int);
+  GET_COLUMN(photcode, "PHOTCODE", short);
+  // XXX free the fits table data here 
+
+  ALLOCATE (measure, MeasureTiny, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    measure[i].dR       = dR[i];
+    measure[i].dD       = dD[i];
+    measure[i].M        = M[i];
+    measure[i].Mcal     = Mcal[i];
+    measure[i].dM       = dM[i];
+    measure[i].airmass  = airmass[i];
+    measure[i].Xccd     = Xccd[i];
+    measure[i].Yccd     = Yccd[i];
+    measure[i].dt       = dt[i];
+    measure[i].t        = t[i];
+    measure[i].averef   = averef[i];
+    measure[i].imageID  = imageID[i];
+    measure[i].dbFlags  = dbFlags[i];
+    measure[i].catID    = catID[i];
+    measure[i].photcode = photcode[i];
+  }
+  fprintf (stderr, "loaded data for %lld measures\n", (long long) Nrow);
+
+  free (dR      );
+  free (dD      );
+  free (M       );
+  free (Mcal    );
+  free (dM      );
+  free (airmass );
+  free (Xccd    );
+  free (Yccd    );
+  free (dt      );
+  free (t       );
+  free (averef  );
+  free (imageID );
+  free (dbFlags );
+  free (catID   );
+  free (photcode);
+
+  catalog->measure = measure;
+  catalog->Nmeasure = Nrow;
+
+  /*** load Average values ***/
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+ 
+  // need to create and assign to flat-field correction
+  GET_COLUMN(R,             "RA",   	   double);
+  GET_COLUMN(D,             "DEC",  	   double);
+  GET_COLUMN(Nmeasure,      "NMEAS",       int);
+  GET_COLUMN(measureOffset, "MEASURE_OFF", int);
+  GET_COLUMN(flags,         "FLAGS",       int);
+  GET_COLUMN(catID,         "CAT_ID",      int);
+  // XXX free the fits table data here 
+
+  ALLOCATE (average, AverageTiny, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    average[i].R              = R[i];
+    average[i].D              = D[i];
+    average[i].Nmeasure       = Nmeasure[i];
+    average[i].measureOffset  = measureOffset[i];
+    average[i].flags          = flags[i];
+    average[i].catID          = catID[i];
+  }
+  fprintf (stderr, "loaded data for %lld averages\n", (long long) Nrow);
+
+  free (R             );
+  free (D             );
+  free (Nmeasure      );
+  free (measureOffset );
+  free (flags         );
+  free (catID         );
+
+  catalog->average = average;
+  catalog->Naverage = Nrow;
+
+  /*** load Secfilt values ***/
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+ 
+  // need to create and assign to flat-field correction
+  GET_COLUMN(M,     "MAG",      float);
+  GET_COLUMN(dM,    "MAG_ERR",  float);
+  GET_COLUMN(Xm,    "MAG_CHI",  float);
+  GET_COLUMN(flags, "FLAGS",    int);
+  GET_COLUMN(Ncode, "NCODE",    short);
+  GET_COLUMN(Nused, "NUSED",    short);
+  GET_COLUMN(M_20,  "MAG_20",   short);
+  GET_COLUMN(M_80,  "MAG_80",   short);
+  // XXX free the fits table data here 
+
+  ALLOCATE (secfilt, SecFilt, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    secfilt[i].M     = M[i];         
+    secfilt[i].dM    = dM[i];
+    secfilt[i].Xm    = Xm[i];
+    secfilt[i].flags = flags[i];
+    secfilt[i].Ncode = Ncode[i];
+    secfilt[i].Nused = Nused[i];
+    secfilt[i].M_20  = M_20[i];
+    secfilt[i].M_80  = M_80[i];
+  }
+  fprintf (stderr, "loaded data for %lld averages\n", (long long) Nrow);
+
+  free (M    );
+  free (dM   );
+  free (Xm   );
+  free (flags);
+  free (Ncode);
+  free (Nused);
+  free (M_20 );
+  free (M_80 );
+
+  catalog->secfilt = secfilt;
+  // assert Nsecfilt * Naverage = Nrow?
+
+  // close files
+
+  return catalog;
+}
+
+// we are passed a BrightCatalog structure, write it to a FITS table (3 ext)
+int BrightCatalogSave(char *filename, BrightCatalog *catalog) {
+
+  int i;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  gfits_init_header (&header);
+  header.extend = TRUE;
+  gfits_create_header (&header);
+  gfits_create_matrix (&header, &matrix);
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file for output %s\n", filename);
+    return FALSE;
+  }
+
+  gfits_fwrite_header  (f, &header);
+  gfits_fwrite_matrix  (f, &matrix);
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  /*** MeasureTiny ***/
+  gfits_create_table_header (&theader, "BINTABLE", "MEASURE_TINY");
+
+  gfits_define_bintable_column (&theader, "E", "RA_OFF",   "ra offset", 	       "arcsec", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "DEC_OFF",  "dec offset",	       "arcsec", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MAG_SYS",  "magnitude (sys)", 	       NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MAG_CAL",  "magnitude (cal)", 	       NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MAG_ERR",  "magnitude (err)", 	       NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "AIRMASS",  "airmass",                  NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "X_CCD",    "ccd x coord",   	       "pix", 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "Y_CCD",    "ccd y coord",   	       "pix", 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "EXPTIME",  "-2.5 * log (exposure time)", "sec",	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "TIME",     "time of exp",              "sec", 	 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "AVE_REF",  "pointer to average table", NULL, 	 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "IMAGE_ID", "image",    		       NULL, 	 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "DB_FLAGS", "flags",    		       NULL, 	 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "CAT_ID",   "catalog",  		       NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "K", "PHOTCODE", "photcode", 		       NULL, 	 1.0, 0.0);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  // create intermediate storage arrays
+  float *dR        ; ALLOCATE (dR      ,  float, catalog->Nmeasure);
+  float *dD        ; ALLOCATE (dD      ,  float, catalog->Nmeasure);
+  float *M         ; ALLOCATE (M       ,  float, catalog->Nmeasure);
+  float *Mcal      ; ALLOCATE (Mcal    ,  float, catalog->Nmeasure);
+  float *dM        ; ALLOCATE (dM      ,  float, catalog->Nmeasure);
+  float *airmass   ; ALLOCATE (airmass ,  float, catalog->Nmeasure);
+  float *Xccd      ; ALLOCATE (Xccd    ,  float, catalog->Nmeasure);
+  float *Yccd      ; ALLOCATE (Yccd    ,  float, catalog->Nmeasure);
+  float *dt        ; ALLOCATE (dt      ,  float, catalog->Nmeasure);
+  int   *t         ; ALLOCATE (t       ,  int  , catalog->Nmeasure);
+  int   *averef    ; ALLOCATE (averef  ,  int  , catalog->Nmeasure);
+  int   *imageID   ; ALLOCATE (imageID ,  int  , catalog->Nmeasure);
+  int   *dbFlags   ; ALLOCATE (dbFlags ,  int  , catalog->Nmeasure);
+  int   *catID     ; ALLOCATE (catID   ,  int  , catalog->Nmeasure);
+  short *photcode  ; ALLOCATE (photcode,  short, catalog->Nmeasure);
+
+  // assign the storage arrays
+  for (i = 0; i < catalog->Nmeasure; i++) {
+    dR[i]       = measure[i].dR       ;
+    dD[i]       = measure[i].dD       ;
+    M[i] 	= measure[i].M        ;
+    Mcal[i]     = measure[i].Mcal     ;
+    dM[i]       = measure[i].dM       ;
+    airmass[i]  = measure[i].airmass  ;
+    Xccd[i]     = measure[i].Xccd     ;
+    Yccd[i]     = measure[i].Yccd     ;
+    dt[i]       = measure[i].dt       ;
+    t[i] 	= measure[i].t        ;
+    averef[i]   = measure[i].averef   ;
+    catID[i]    = measure[i].catID    ;
+    imageID[i]  = measure[i].imageID  ;
+    dbFlags[i]  = measure[i].dbFlags  ;
+    photcode[i] = measure[i].photcode ;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "RA_OFF",   dR,       catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "DEC_OFF",  dD,       catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_SYS",  M,        catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_CAL",  Mcal,     catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_ERR",  dM,       catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "AIRMASS",  airmass,  catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "X_CCD",    Xccd,     catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "Y_CCD",    Yccd,     catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "EXPTIME",  dt,       catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "TIME",     t,        catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "AVE_REF",  averef,   catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "IMAGE_ID", imageID,  catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "DB_FLAGS", dbFlags,  catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "CAT_ID",   catID,    catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "PHOTCODE", photcode, catalog->Nmeasure);
+
+  free (dR      );
+  free (dD      );
+  free (M       );
+  free (Mcal    );
+  free (dM      );
+  free (airmass );
+  free (Xccd    );
+  free (Yccd    );
+  free (dt      );
+  free (t       );
+  free (averef  );
+  free (imageID );
+  free (dbFlags );
+  free (catID   );
+  free (photcode);
+
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table  (f, &ftable);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  /*** AverageTiny ***/
+  gfits_create_table_header (&theader, "BINTABLE", "AVERAGE_TINY");
+
+  gfits_define_bintable_column (&theader, "D", "RA",   	      "ra (J2000)", 	       "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "DEC",  	      "dec (J2000)",	       "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "NMEAS",       "number of measures",     NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "MEASURE_OFF", "index to measurements",  NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "FLAGS",       "flags",                  NULL, 	 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "CAT_ID",      "catalog ref",            NULL, 	 1.0, 0.0);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  // create intermediate storage arrays
+  double *R             ; ALLOCATE (R,             double, catalog->Naverage);
+  double *D             ; ALLOCATE (D,             double, catalog->Naverage);
+  int   *Nmeasure       ; ALLOCATE (Nmeasure,      int,    catalog->Naverage);
+  int   *measureOffset  ; ALLOCATE (measureOffset, int,    catalog->Naverage);
+  int   *flags          ; ALLOCATE (flags,         int,    catalog->Naverage);
+  int   *catID          ; ALLOCATE (catID,         int,    catalog->Naverage);
+
+  // assign the storage arrays
+  for (i = 0; i < catalog->Nmeasure; i++) {
+      R[i]           	= average[i].R       ;
+      D[i]           	= average[i].D       ;
+      Nmeasure[i]    	= average[i].Nmeasure;
+      measureOffset[i]  = average[i].measureOffset;
+      flags[i]          = average[i].flags;
+      catID[i]          = average[i].catID;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "RA",          R,             catalog->Naverage);
+  gfits_set_bintable_column (&theader, &ftable, "DEC",         D,             catalog->Naverage);
+  gfits_set_bintable_column (&theader, &ftable, "NMEAS",       Nmeasure,      catalog->Naverage);
+  gfits_set_bintable_column (&theader, &ftable, "MEASURE_OFF", measureOffset, catalog->Naverage);
+  gfits_set_bintable_column (&theader, &ftable, "FLAGS",       flags,         catalog->Naverage);
+  gfits_set_bintable_column (&theader, &ftable, "CAT_ID",      catID,         catalog->Naverage);
+
+  free (R             );
+  free (D             );
+  free (Nmeasure      );
+  free (measureOffset );
+  free (flags         );
+  free (catID         );
+
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table  (f, &ftable);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  /*** SecFilt ***/
+  gfits_create_table_header (&theader, "BINTABLE", "SECFILT");
+
+  gfits_define_bintable_column (&theader, "E", "MAG",      "ra offset",                "arcsec", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MAG_ERR",  "dec offset",               "arcsec", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MAG_CHI",  "magnitude (sys)",          NULL,     1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "FLAGS",    "magnitude (cal)",          NULL,     1.0, 0.0);
+  gfits_define_bintable_column (&theader, "I", "NCODE",    "magnitude (err)",          NULL,     1.0, 0.0);
+  gfits_define_bintable_column (&theader, "I", "NUSED",    "airmass",                  NULL,     1.0, 0.0);
+  gfits_define_bintable_column (&theader, "I", "MAG_20",   "ccd x coord",              "pix",    1.0, 0.0);
+  gfits_define_bintable_column (&theader, "I", "MAG_80",   "ccd y coord",              "pix",    1.0, 0.0);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  // create intermediate storage arrays
+  float *M        ; ALLOCATE (M      ,  float, catalog->Nmeasure);
+  float *dM       ; ALLOCATE (dM     ,  float, catalog->Nmeasure);
+  float *Xm       ; ALLOCATE (Xm     ,  float, catalog->Nmeasure);
+  int   *flags    ; ALLOCATE (flags  ,  int,   catalog->Nmeasure);
+  short *Ncode    ; ALLOCATE (Ncode  ,  short, catalog->Nmeasure);
+  short *Nused    ; ALLOCATE (Nused  ,  short, catalog->Nmeasure);
+  short *M_20     ; ALLOCATE (M_20   ,  short, catalog->Nmeasure);
+  short *M_80     ; ALLOCATE (M_80   ,  short, catalog->Nmeasure);
+
+  // assign the storage arrays
+  for (i = 0; i < catalog->Nmeasure; i++) {
+    M     [i]       = secfilt[i]. M      ;
+    dM    [i]       = secfilt[i]. dM     ;
+    Xm    [i]       = secfilt[i]. Xm     ;
+    flags [i]       = secfilt[i]. flags  ;
+    Ncode [i]       = secfilt[i]. Ncode  ;
+    Nused [i]       = secfilt[i]. Nused  ;
+    M_20  [i]       = secfilt[i]. M_20   ;
+    M_80  [i]       = secfilt[i]. M_80   ;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "MAG",      M     ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_ERR",  dM    ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_CHI",  Xm    ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "FLAGS",    flags ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "NCODE",    Ncode ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "NUSED",    Nused ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_20",   M_20  ,catalog->Nmeasure);
+  gfits_set_bintable_column (&theader, &ftable, "MAG_80",   M_80  ,catalog->Nmeasure);
+
+  free (M      );
+  free (dM     );
+  free (Xm     );
+  free (flags  );
+  free (Ncode  );
+  free (Nused  );
+  free (M_20   );
+  free (M_80   );
+
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table  (f, &ftable);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  return TRUE;
+}
+
+BrightCatalog *BrightCatalogMerge (Catalog *catalog, int Ncatalog) {
+
+  BrightCatalog *bcatalog = NULL;
+  ALLOCATE (bcatalog, BrightCatalog, 1);
+  
+  int Nmeas = 0;
+  int Naves = 0;
+  for (i = 0; i < Ncatalog; i++) {
+    Nmeas += catalog[i].Nmeasure;
+    Naves += catalog[i].Naverage;
+  }
+    
+  ALLOCATE (bcatalog[0].measure, MeasureTiny, Nmeas);
+  ALLOCATE (bcatalog[0].average, AverageTiny, Naves);
+
+  int Nm = 0;
+  int Na = 0;
+  for (i = 0; i < Ncatalog; i++) {
+    for (j = 0; j < catalog[i].Naverage; j++) {
+      bcatalog[0].average[Na] = catalog[i].average[j];
+      for (k = 0; k < Nsecfilt; k++) {
+	bcatalog[0].secfilt[Nsecfilt*Na + k] = catalog[i].secfilt[Nsecfilt*j + k];
+      }
+      Na++;
+      assert (Na <= Naves);
+    }
+    for (j = 0; j < catalog[i].Nmeasure; j++) {
+      bcatalog[0].measure[Nm] = catalog[i].measure[j];
+      Nm++;
+      assert (Nm <= Nmeas);
+    }
+  }
+  return bcatalog;
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/ImageSubset.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/ImageSubset.c	(revision 33244)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/ImageSubset.c	(revision 33244)
@@ -0,0 +1,168 @@
+# include "relphot.h"
+
+// this is (nearly?) identical to the one in 'uniphot/src' used by setphot / setphot_client
+// there may be difference in the specific columns used, however (if not, we can move to libdvo?)
+ImageSubset *ImageSubsetLoad(char *filename, off_t *nimage) {
+
+  int i, Ncol, Ncol2;
+  off_t Nrow;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  *nimage = 0;
+  ImageSubset *image = NULL;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+  
+  // XXX close the fits file here
+
+  // a bit annoying : we read the entire block of data (180M), then extract the columns, then set the image structure values.
+  // this means I need 3 copies in memory at some point.  ugh.
+
+  char type[16];
+
+  // need to create and assign to flat-field correction
+  float *Mcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL", type, &Nrow, &Ncol);
+  myAssert (!strcmp(type, "float"), "wrong column type");
+
+  float *dMcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL_ERR", type, &Nrow, &Ncol2);
+  myAssert (!strcmp(type, "float"), "wrong column type");
+  myAssert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *imageID = gfits_get_bintable_column_data (&theader, &ftable, "IMAGE_ID", type, &Nrow, &Ncol2);
+  myAssert (!strcmp(type, "int"), "wrong column type");
+  myAssert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *map = gfits_get_bintable_column_data (&theader, &ftable, "PHOTOM_MAP", type, &Nrow, &Ncol2);
+  myAssert (!strcmp(type, "int"), "wrong column type");
+  myAssert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *flags = gfits_get_bintable_column_data (&theader, &ftable, "FLAGS", type, &Nrow, &Ncol2);
+  myAssert (!strcmp(type, "int"), "wrong column type");
+  myAssert (Ncol == Ncol2, "table length mismatch");
+
+  // XXX free the fits table data here 
+
+  ALLOCATE (image, ImageSubset, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    image[i].imageID       = imageID[i];
+    image[i].photom_map_id = map[i];
+    image[i].flags         = flags[i];
+    image[i].Mcal          = Mcal[i];
+    image[i].dMcal         = dMcal[i];
+  }
+  fprintf (stderr, "loaded data for %lld images\n", (long long) Nrow);
+
+  free (Mcal);
+  free (dMcal);
+  free (imageID);
+  free (map);
+  free (flags);
+
+  *nimage = Nrow;
+  return image;
+}
+
+int ImageSubsetSave(char *filename, Image *image, off_t Nimage) {
+
+  int i;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  gfits_init_header (&header);
+  header.extend = TRUE;
+  gfits_create_header (&header);
+  gfits_create_matrix (&header, &matrix);
+
+  gfits_create_table_header (&theader, "BINTABLE", "IMAGE_SUBSET");
+
+  gfits_define_bintable_column (&theader, "E", "MCAL", "zero point offset", "magnitudes", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MCAL_ERR", "zero point error", "magnitudes", 1.0, 0.0);
+
+  // an unsigned int needs to have bzero of 0x8000
+  gfits_define_bintable_column (&theader, "J", "IMAGE_ID", "image ID", NULL, 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "PHOTOM_MAP", "map", NULL, 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "FLAGS", "flags", NULL, 1.0, 1.0*0x8000);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  float *Mcal, *dMcal;
+  unsigned int *imageID, *map, *flags;
+
+  // create intermediate storage arrays
+  ALLOCATE (Mcal,  float, Nimage);
+  ALLOCATE (dMcal, float, Nimage);
+  ALLOCATE (imageID, unsigned int, Nimage);
+  ALLOCATE (map,     unsigned int, Nimage);
+  ALLOCATE (flags,   unsigned int, Nimage);
+
+  // assign the storage arrays
+  for (i = 0; i < Nimage; i++) {
+    imageID[i] = image[i].imageID;
+    map[i]     = image[i].photom_map_id;
+    flags[i]   = image[i].flags;
+    Mcal[i]    = image[i].Mcal;
+    dMcal[i]   = image[i].dMcal;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "MCAL",       Mcal,    Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "MCAL_ERR",   dMcal,   Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "IMAGE_ID",   imageID, Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "PHOTOM_MAP", map,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "FLAGS",      flags,   Nimage);
+
+  free (Mcal);
+  free (dMcal);
+  free (imageID);
+  free (map);
+  free (flags);
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file for output %s\n", filename);
+    return FALSE;
+  }
+
+  gfits_fwrite_header  (f, &header);
+  gfits_fwrite_matrix  (f, &matrix);
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table  (f, &ftable);
+
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/args.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/args.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/args.c	(revision 33244)
@@ -265,2 +265,61 @@
   return TRUE;
 }
+
+int args_client (int argc, char **argv) {
+
+  int N;
+
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  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) relphot_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) relphot_client_usage();
+
+  CATDIR[0] = 0;
+  if ((N = get_argument (argc, argv, "-catdir"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (CATDIR, argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!CATDIR[0]) relphot_client_usage();
+
+  IMAGES = NULL; // used in -update mode
+  BCATALOG = NULL; // used in -load mode
+  MODE = MODE_NONE;
+  if ((N = get_argument (argc, argv, "-load"))) {
+    MODE = MODE_LOAD;
+    remove_argument (N, &argc, argv);
+    BCATALOG = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-update"))) {
+    if (MODE) {
+      fprintf (stderr, "ERROR: cannot use both -load and -update options!\n");
+      usage();
+    }
+    MODE = MODE_UPDATE;
+    remove_argument (N, &argc, argv);
+    IMAGES = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!MODE) relphot_client_usage();
+
+  if (argc != 1) relphot_client_usage ();
+
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/help.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/help.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/help.c	(revision 33244)
@@ -44,2 +44,30 @@
 }
 
+void relphot_client_usage (void) {
+  fprintf (stderr, "ERROR: USAGE: relphot -load -bcatalog (filename) -hostID (hostID) -hostdir (hostdir) -catdir (catdir)\n");
+  fprintf (stderr, "       or:    relphot -update -images (filename) -hostID (hostID) -hostdir (hostdir) -catdir (catdir)\n");
+  fprintf (stderr, "  use -h for more usage information\n");
+  exit (2);
+} 
+
+void relphot_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;
+  if (argc == 1) relphot_client_usage();
+  return;
+
+show_help:
+  fprintf (stderr, "USAGE: relphot_client [-load / -update] (db info)\n\n");
+  fprintf (stderr, "       relphot_client -load (bcatalog) : extract the bright catalog subset from client's tables\n");
+  fprintf (stderr, "                            (bcatalog) : location where the bright subset is saved\n");
+  fprintf (stderr, "       relphot_client -update (images) : apply calculated zero points to the client's tables\n\n");
+  fprintf (stderr, "                              (images) : location of the table with the image zero points\n");
+  fprintf (stderr, "       db info : -hostID (hostID) -hostdir (hostdir) -catdir (catdir)\n");
+  fprintf (stderr, "other options:\n");
+  fprintf (stderr, "  -v : verbose output\n");
+  fprintf (stderr, "  \n");
+  exit (2);
+}
+
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/initialize.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/initialize.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/initialize.c	(revision 33244)
@@ -95,2 +95,11 @@
   srand48(B);
 }
+
+void initialize_relphot_client (int argc, char **argv) {
+
+  int N;
+
+  relphot_client_help (argc, argv);
+  // ConfigInit (&argc, argv); XXX not sure if we need anything in here (maybe photcode table)
+  args_client (argc, argv);
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/load_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/load_catalogs.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/load_catalogs.c	(revision 33244)
@@ -1,11 +1,27 @@
 # include "relphot.h"
 
-Catalog *load_catalogs (SkyList *skylist, int *Ncatalog) {
+// this function loops over the catalogs, loads the data, and extracts a bright subset
+// the returned array (catalog, Ncatalog) has the same layout as the full database, but
+// only a subset of the detetions & objects
+
+// if this function is called in parallel mode, it in turn calls load_catalogs_parallel,
+// which distributes the work to the remote hosts and loads their results
+
+// if this function is called with a specified hostID, then only the fraction of the
+// database hosted by that hostID is loaded
+Catalog *load_catalogs (SkyList *skylist, int *Ncatalog, int hostID, char *hostpath) {
 
   off_t i, Nmeas, Nstar, Nmeas_total, Nstar_total;
   Catalog *catalog, tcatalog;
 
+  // XXX need to decide how to determine PARALLEL mode...
+  if (PARALLEL & !hostID) {
+    catalog = load_catalogs_parallel (skylist, Ncatalog);
+    return catalog;
+  }
+
   if (VERBOSE2) fprintf (stderr, "loading catalog data\n");
 
+  // a bit of an over-alloc, since we don't load all catalogs for a region 
   ALLOCATE (catalog, Catalog, skylist[0].Nregions);
 
@@ -16,6 +32,11 @@
     dvo_catalog_init (&catalog[i], TRUE);
 
+    if (hostID && (skylist[0].regions[i]->hostID != hostID)) continue;
+
     // set up the basic catalog info
-    tcatalog.filename = skylist[0].filename[i];
+    char hostfile[1024];
+    snprintf (hostfile, 1024, "%s/%s.cpt", hostpath, skylist[0].regions[i]->name);
+    tcatalog.filename = hostID ? hostfile : skylist[0].filename[i];
+
     tcatalog.catformat = dvo_catalog_catformat (CATFORMAT);    // set the default catformat from config data
     tcatalog.catmode   = dvo_catalog_catmode (CATMODE);        // set the default catmode from config data
@@ -67,2 +88,139 @@
    need to use an XCLD lock here.  
 */
+
+// CATDIR is supplied globally
+Catalog *load_catalogs_parallel (SkyTable *sky, int *Ncatalog) {
+
+  // launch the setphot_client jobs to the parallel hosts
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    char catalogFile[512];
+    snprintf (catalogFile, 512, "%s/relphot.catalog.subset.dat", table->hosts[i].pathname);
+
+    char command[1024];
+    snprintf (command, 1024, "relphot_client -test -load %s -hostID %d -catdir %s -hostdir %s", 
+	      catalogFile, table->hosts[i].hostID, CATDIR, table->hosts[i].pathname);
+
+    fprintf (stderr, "command: %s\n", command);
+
+    // 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
+
+    // check that all hosts started OK?
+  }
+
+  // watch for stdout / stderr from those jobs...
+  // wait for all of them to complete...
+
+  // each host generates a BrightCatalog structure, with the measure, average, etc value loaded into a single 
+  // set of arrays (of MeasureTiny, AverageTiny, Secfilt).  I need to split out the
+  // per-catalog measurements into separate catalog entries.
+
+  // we don't know how many catalogs we actually need.  allocate a single entry, then
+  // below we will allocate the max number needed after the BrightCatalog is loaded
+  int Ncatalog = 0;
+  int NCATALOG = 1;
+  ALLOCATE (catalog, Catalog, NCATALOG);
+
+  int *NAVERAGE;
+  int *NMEASURE;
+  ALLOCATE (NAVERAGE, int, NCATALOG);
+  ALLOCATE (NMEASURE, int, NCATALOG);
+  for (i = 0; i < NCATALOG; i++) {
+    NAVERAGE[i] = 100;
+    NMEASURE[i] = 100;
+    catalog[i].Naverage = 0;
+    catalog[i].Nmeasure = 0;
+    ALLOCATE (catalog[i].averageT, AverageTiny, NAVERAGE[i]);
+    ALLOCATE (catalog[i].measureT, MeasureTiny, NMEASURE[i]);
+    ALLOCATE (catalog[i].secfilt, SecFilt, Nsecfilt*NAVERAGE[i]);
+  }
+
+  for (i = 0; i < table->Nhosts; i++) {
+
+    // XXX save this name in table->hosts[]?  it is created above as well...
+    char catalogFile[512];
+    snprintf (catalogFile, 512, "%s/relphot.catalog.subset.dat", table->hosts[i].pathname);
+
+    BrightCatalog *bcatalog = BrightCatalogLoad (catalogFile);
+    assert (bcatalog);
+    
+    // XXX put the code below into a function equivalent to BrightCatalogMerge?
+
+    // find the max value of catID and realloc to match that (check measure & average or
+    // just average?)
+    int catIDmax = 0;
+    for (j = 0; j < bcatalog->Naverage; j++) {
+      catIDmax = MAX(catIDmax, bcatalog->average[j].catID);
+    }
+    // XXX validate the measure ID range here
+    
+    int NCATALOG_OLD = NCATALOG;
+    NCATALOG = MAX (NCATALOG, catIDmax);
+    REALLOCATE (catalog, Catalog, NCATALOG);
+    
+    REALLOCATE (NAVERAGE, int, NCATALOG);
+    REALLOCATE (NMEASURE, int, NCATALOG);
+    for (i = NCATALOG_OLD; i < NCATALOG; i++) {
+      NAVERAGE[i] = 100;
+      NMEASURE[i] = 100;
+      catalog[i].Naverage = 0;
+      catalog[i].Nmeasure = 0;
+      ALLOCATE (catalog[i].averageT, AverageTiny, NAVERAGE[i]);
+      ALLOCATE (catalog[i].measureT, MeasureTiny, NMEASURE[i]);
+      ALLOCATE (catalog[i].secfilt, SecFilt, Nsecfilt*NAVERAGE[i]);
+    }
+
+    // each bcatalog (from each host) has a different set of catID ranges
+    // they also (probably) have contiguous ranges.  But, it is a bit tricky to be sure I
+    // can use that info, so perhaps ignore it
+
+    // assign the averages to the corresponding catalog
+    for (j = 0; j < bcatalog->Naverage; j++) {
+      Nc = bcatalog->average[j].catID;
+      assert (Nc < NCATALOG);
+      Na = catalog[Nc].Naverage;
+      catalog[Nc].averageT[Na] = bcatalog->average[j];
+
+      // secfilt entries are grouped in blocks for each average
+      for (k = 0; k < Nsecfilt; k++) {
+	catalog[Nc].secfilt[Na*Nsecfilt + k] = bcatalog->secfilt[j*Nsecfilt + k];
+      }      
+
+      catalog[Nc].Naverage ++;
+      if (catalog[Nc].Naverage >= NAVERAGE[N]) {
+	NAVERAGE[Nc] += 100;
+	REALLOCATE (catalog[Nc].averageT, AverageTiny, NAVERAGE[Nc]);
+	REALLOCATE (catalog[Nc].secfilt, SecFilt, Nsecfilt*NAVERAGE[Nc]);
+      }	       
+    }
+
+    // assign the measures to the corresponding catalog
+    // XXX what about averef and related links?  Do I need them?
+    for (j = 0; j < bcatalog->Nmeasure; j++) {
+      Nc = bcatalog->measure[j].catID;
+      assert (Nc < NCATALOG);
+      Na = catalog[Nc].Nmeasure;
+      catalog[Nc].measureT[Na] = bcatalog->measure[j];
+      catalog[Nc].Nmeasure ++;
+      if (catalog[Nc].Nmeasure >= NMEASURE[N]) {
+	NMEASURE[Nc] += 100;
+	REALLOCATE (catalog[Nc].measureT, MeasureTiny, NMEASURE[Nc]);
+      }	       
+    }
+    // XXX free the input bcatalog entries
+  }
+  *Ncatalog = NCATALOG;
+  return (catalog);
+}      
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/reload_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/reload_catalogs.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/reload_catalogs.c	(revision 33244)
@@ -94,2 +94,44 @@
   fprintf (stderr, "time7  %f : free catalog\n", time7);
 }
+
+int reload_catalogs_parallel (SkyTable *sky, Image *image, off_t Nimage) {
+
+  // write out the subset table of image information
+  char imageFile[512];
+  snprintf (imageFile, 512, "%s/Images.subset.dat", CATDIR);
+  if (!ImageSubsetSave (imageFile, image, Nimage)) {
+    fprintf (stderr, "failed to write image subset\n");
+    exit (1);
+  }
+
+  // now launch the relphot_client jobs to the parallel hosts
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    char command[1024];
+    snprintf (command, 1024, "relphot_client -reload -hostname %s -catdir %s -hostdir %s -images %s", 
+	      table->hosts[i].hostname, CATDIR, table->hosts[i].pathname, imageFile);
+
+    fprintf (stderr, "command: %s\n", command);
+
+    // 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
+
+    // check that all hosts started OK?
+  }
+
+  // watch for stdout / stderr from those jobs...
+  // wait for all of them to complete...
+
+  return (TRUE);
+}      
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot.c	(revision 33244)
@@ -241,5 +241,9 @@
 
   /* load catalog data from region files, update Mrel include all data */
-  reload_catalogs (skylist, flatcorr);
+  if (PARALLEL) {
+    reload_catalogs_parallel ();
+  } else {
+    reload_catalogs (skylist, flatcorr);
+  }
   MARKTIME("-- updated all catalogs: %f sec\n", dtime);
 
Index: /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot_client.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot_client.c	(revision 33244)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/relphot/src/relphot_client.c	(revision 33244)
@@ -0,0 +1,62 @@
+# include "relphot.h"
+
+// relphot_client is run on a remote host and is responsible for updating the catalogs
+// owned by that host.  
+
+// there are two modes:
+
+// relphot_client -load : extract the bright catalog subset from the client's tables and
+//                        save to a local FITS table for relphot to load and used
+
+// (relphot loads the bright catalog subsets from all clients, then uses this to determine
+// the per-image zero points (and potentially the flat-field corrections)
+
+// relphot_client -update : load image table containing the update zero point information
+//                          and apply this to the client's tables
+
+int main (int argc, char **argv) {
+
+  // get configuration info, args, lockfile (set CATDIR, HOSTDIR, HOSTNAME, IMAGES) 
+  // XXX pass in both HOSTDIR and HOSTID or just HOSTNAME (and read the host table)?
+  initialize_relphot_client (argc, argv);
+
+  // need to supply the region selected by the calling program -> UserPatch
+
+  // load the current sky table (layout of all SkyRegions) 
+  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, TRUE, -1, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+  
+  switch (MODE) {
+    case MODE_LOAD: {
+      // need to pass in HOSTDIR, HOST_ID,
+      Catalog *catalog = load_catalogs (skylist, &Ncatalog, HOST_ID, HOSTDIR);
+   
+      BrightCatalog *bcatalog = BrightCatalogMerge (Catalog *catalog, int Ncatalog);
+
+      if (!BrightCatalogSave (BCATALOG, bcatalog)) {
+	abort();
+      }
+      break;
+    }
+      
+    case MODE_UPDATE: {
+      // load the image subset table from the specified location
+      off_t Nimage;
+      ImageSubset *image = ImageSubsetLoad (IMAGES, &Nimage);
+      
+      // load the flat-field correction table from CATDIR
+      char flatcorrFile[1024];
+      snprintf (flatcorrFile, 1024, "%s/flatcorr.fits", CATDIR);
+      FlatCorrectionTable *flatcorrTable = FlatCorrectionLoad (flatcorrFile, VERBOSE);
+      break;
+    }
+
+    default:
+      fprintf (stderr, "impossible!");
+      abort();
+  }
+
+  exit (0);
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c	(revision 33243)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c	(revision 33244)
@@ -29,29 +29,2 @@
   exit (0);
 }
-  
-
-/* setphot : set the zero points for images in the db (perhaps based on external information)
-   setphot (zpt_table)
-
-   setphot has 2 modes : basic & ubercal
-
-   * outline of basic mode:
-
-   ** load text table of zpts, time (photcode?)
-   ** load images
-   ** match images to zpts
-   ** set zpts
-   ** load catalogs
-   ** update detection (& averages?)
-
-   * outline of ubercal mode:
-
-   ** load fits table of zpts & time + table of flat-field corrections
-   ** load images
-   ** match images to zpts
-   ** set zpts
-   ** load catalogs
-   ** update detection (& averages?)
-
- */
-
