Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/args_loadICRF.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/args_loadICRF.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/args_loadICRF.c	(revision 37567)
@@ -0,0 +1,227 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+static void help (void);
+static void help_client (void);
+
+AddstarClientOptions args_loadstarpar (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /* basic mode: image, list, refcat */
+  options.mode = ADDSTAR_MODE_REFCAT;
+
+  /* we do not allow a subset to be extracted -- all or nothing, babe */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+
+  // XXX for the moment, make this selection manual.  it needs to be automatic 
+  // based on the state of the SkyTable
+  HOST_ID = 0;
+  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);
+  }
+
+  /* only add to existing regions */
+  options.existing_regions = FALSE;
+  if ((N = get_argument (argc, argv, "-existing-regions"))) {
+    options.existing_regions = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* other addstar options which cannot be used in loadstarpar */
+  options.photcode = 0;
+  options.timeref = 0; 
+  options.mosaic = FALSE;
+  options.skip_missed = FALSE;
+  options.closest = FALSE;
+  options.nosort = FALSE;
+  options.update = FALSE;
+  options.only_images = FALSE;
+  options.calibrate = FALSE;
+  options.quality_airmass = FALSE;
+  ACCEPT_ASTROM = FALSE;
+  FORCE_READ = FALSE;
+  TEXTMODE = FALSE;
+  SUBPIX = FALSE;
+  DUMP = NULL;
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: loadstarpar [options] (fitsfile) [..more files]\n");
+    exit (2);
+  }
+  return (options);
+}
+
+AddstarClientOptions args_loadstarpar_client (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  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) help_client();
+
+  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) help_client();
+
+  CPT_FILE = NULL;
+  if ((N = get_argument (argc, argv, "-cpt"))) {
+    remove_argument (N, &argc, argv);
+    CPT_FILE = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!CPT_FILE) help_client();
+  
+  INPUT = NULL;
+  if ((N = get_argument (argc, argv, "-input"))) {
+    remove_argument (N, &argc, argv);
+    INPUT = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!INPUT) help_client();
+
+  /* we do not allow a subset to be extracted -- all or nothing, babe */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* other addstar options which cannot be used in loadstarpar */
+  options.photcode = 0;
+  options.timeref = 0; 
+  options.mosaic = FALSE;
+  options.skip_missed = FALSE;
+  options.closest = FALSE;
+  options.nosort = FALSE;
+  options.update = FALSE;
+  options.only_images = FALSE;
+  options.calibrate = FALSE;
+  options.quality_airmass = FALSE;
+  ACCEPT_ASTROM = FALSE;
+  FORCE_READ = FALSE;
+  TEXTMODE = FALSE;
+  SUBPIX = FALSE;
+  DUMP = NULL;
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: loadstarpar_client -cpt (file) -input (file)\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE: loadstarpar [options] (file) [..more files]\n");
+  fprintf (stderr, "  add data from stellar parameter file to DVO\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
+
+static void help_client () {
+
+  fprintf (stderr, "USAGE: loadstarpar_client -D CATDIR catdir -hostID ID -hostdir (dir) -cpt (filename) -input (input) [options]\n");
+  fprintf (stderr, "  add data from stellar parameter file to DVO\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF.c	(revision 37567)
@@ -0,0 +1,54 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+/* This is the DVO program to upload Greg Green's stellar parametersq into a DVO database.
+   It is modeled on the loadwise program and is expected to be run only rarely (once?).
+   The stellar parameter data are delivered as *.fits files.  It does not allow a subset
+   of the sky to be uploaded; entire stellar parameter files are loaded if supplied on the
+   command line.
+
+   USAGE: loadstarpar -D CATDIR (catdir) (file.fits) [...more files]
+*/
+
+int main (int argc, char **argv) {
+
+  int i;
+  AddstarClientOptions options;
+
+  // need to construct these options with args_loadstarpar...
+  options = ConfigInit (&argc, argv);
+  options = args_loadstarpar (argc, argv, options);
+
+  // load the full sky description table (dvodb must exist)
+  SkyTable *sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, FALSE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  // load the list of hosts
+  HostTable *hosts = NULL;
+  if (PARALLEL) {
+    hosts = HostTableLoad (CATDIR, sky->hosts);
+    if (!hosts) {
+      fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", sky->hosts, CATDIR);
+      exit (1);
+    }    
+
+    // ensure that the paths are absolute path names
+    for (i = 0; i < hosts->Nhosts; i++) {
+      char *tmppath = abspath (hosts->hosts[i].pathname, DVO_MAX_PATH);
+      free (hosts->hosts[i].pathname);
+      hosts->hosts[i].pathname = tmppath;
+    }
+
+    // set up the array of active hosts
+    init_remote_hosts ();
+  }
+
+  // generate the subset matching the user-selected region
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  for (i = 1; i < argc; i++) {
+    fprintf (stderr, "loading %s\n", argv[i]);
+    loadstarpar_table (skylist, hosts, argv[i], &options);
+  }
+  exit (0);
+}  
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_catalog.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_catalog.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_catalog.c	(revision 37567)
@@ -0,0 +1,28 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+int loadstarpar_catalog (StarPar_Stars *stars, int Nstars, SkyRegion *region, char *filename, AddstarClientOptions *options) {
+
+  Catalog catalog;
+
+  // now we have all of the loaded stars in this catalog
+  catalog.filename = filename;
+  catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+  catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+  catalog.catflags = LOAD_AVES | LOAD_SECF | LOAD_STARPAR;
+  catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    
+  // an error exit status here is a significant error
+  if (!dvo_catalog_open (&catalog, region, VERBOSE, "w")) {
+    fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+    exit (2);
+  }
+
+  find_matches_starpar (region, stars, Nstars, &catalog, options);
+    
+  dvo_catalog_save (&catalog, VERBOSE);
+  dvo_catalog_unlock (&catalog);
+  dvo_catalog_free (&catalog);
+
+  return (TRUE);
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_client.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_client.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_client.c	(revision 37567)
@@ -0,0 +1,27 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+int main (int argc, char **argv) {
+
+  AddstarClientOptions options;
+
+  // need to construct these options with args_loadstarpar...
+  options = ConfigInit (&argc, argv);
+  options = args_loadstarpar_client (argc, argv, options);
+
+  // client is called with a pointer to the file to be loaded
+
+  SkyTable *sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, FALSE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  SkyList *skylist = SkyRegionByCPT (sky, CPT_FILE);
+
+  int Nstars;
+  StarPar_Stars *stars = loadstarpar_load_stars (INPUT, &Nstars);
+
+  loadstarpar_catalog (stars, Nstars, skylist->regions[0], CPT_FILE, &options);
+
+  free (stars);
+
+  exit (0);
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_io.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_io.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_io.c	(revision 37567)
@@ -0,0 +1,191 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+int loadstarpar_save_stars (char *filename, StarPar_Stars *stars, int Nstars) {
+
+  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) {
+    myAbortF ("ERROR: cannot open file for output %s\n", filename);
+  }
+
+  gfits_fwrite_header  (f, &header);
+  gfits_fwrite_matrix  (f, &matrix);
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  gfits_create_table_header (&theader, "BINTABLE", "STARPAR");
+
+  gfits_define_bintable_column (&theader, "D", "RA",       "", "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "DEC",      "", "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "GLON",     "", "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "GLAT",     "", "degree", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "Ebv",      "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "dEbv",     "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "DistMag",  "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "dDistMag", "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "M_r",      "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "dM_r",     "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "FeH",      "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "dFeH",     "", "", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J", "averef",   "", "", 1.0, FT_BZERO_INT32);
+  gfits_define_bintable_column (&theader, "J", "objID",    "", "", 1.0, FT_BZERO_INT32);
+  gfits_define_bintable_column (&theader, "J", "catID",    "", "", 1.0, FT_BZERO_INT32);
+
+  int i;
+  double       *ra       = NULL; ALLOCATE (ra      , double	 , Nstars); for (i = 0; i < Nstars; i++) ra      [i] = stars[i].starpar.R ;
+  double       *dec      = NULL; ALLOCATE (dec     , double	 , Nstars); for (i = 0; i < Nstars; i++) dec     [i] = stars[i].starpar.D ;
+  float        *glon     = NULL; ALLOCATE (glon    , float 	 , Nstars); for (i = 0; i < Nstars; i++) glon    [i] = stars[i].starpar.galLon  ;
+  float        *glat     = NULL; ALLOCATE (glat    , float 	 , Nstars); for (i = 0; i < Nstars; i++) glat    [i] = stars[i].starpar.galLat  ;
+  float        *Ebv      = NULL; ALLOCATE (Ebv     , float	 , Nstars); for (i = 0; i < Nstars; i++) Ebv     [i] = stars[i].starpar.Ebv     ;
+  float        *dEbv     = NULL; ALLOCATE (dEbv    , float	 , Nstars); for (i = 0; i < Nstars; i++) dEbv    [i] = stars[i].starpar.dEbv    ;
+  float        *DistMag  = NULL; ALLOCATE (DistMag , float	 , Nstars); for (i = 0; i < Nstars; i++) DistMag [i] = stars[i].starpar.DistMag ;
+  float        *dDistMag = NULL; ALLOCATE (dDistMag, float	 , Nstars); for (i = 0; i < Nstars; i++) dDistMag[i] = stars[i].starpar.dDistMag;
+  float        *M_r      = NULL; ALLOCATE (M_r     , float	 , Nstars); for (i = 0; i < Nstars; i++) M_r     [i] = stars[i].starpar.M_r     ;
+  float        *dM_r     = NULL; ALLOCATE (dM_r    , float	 , Nstars); for (i = 0; i < Nstars; i++) dM_r    [i] = stars[i].starpar.dM_r    ;
+  float        *FeH      = NULL; ALLOCATE (FeH     , float	 , Nstars); for (i = 0; i < Nstars; i++) FeH     [i] = stars[i].starpar.FeH     ;
+  float        *dFeH     = NULL; ALLOCATE (dFeH    , float	 , Nstars); for (i = 0; i < Nstars; i++) dFeH    [i] = stars[i].starpar.dFeH    ;
+  unsigned int *averef   = NULL; ALLOCATE (averef  , unsigned int, Nstars); for (i = 0; i < Nstars; i++) averef  [i] = stars[i].starpar.averef  ;
+  unsigned int *objID    = NULL; ALLOCATE (objID   , unsigned int, Nstars); for (i = 0; i < Nstars; i++) objID   [i] = stars[i].starpar.objID   ;
+  unsigned int *catID    = NULL; ALLOCATE (catID   , unsigned int, Nstars); for (i = 0; i < Nstars; i++) catID   [i] = stars[i].starpar.catID   ;
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "RA",       ra      , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "DEC",      dec     , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "GLON",     glon    , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "GLAT",     glat    , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "Ebv",      Ebv     , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "dEbv",     dEbv    , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "DistMag",  DistMag , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "dDistMag", dDistMag, Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "M_r",      M_r     , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "dM_r",     dM_r    , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "FeH",      FeH     , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "dFeH",     dFeH    , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "averef",   averef  , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "objID",    objID   , Nstars);
+  gfits_set_bintable_column (&theader, &ftable, "catID",    catID   , Nstars);
+    
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table (f, &ftable);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  return TRUE;
+}
+
+
+# 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");
+
+StarPar_Stars *loadstarpar_load_stars (char *filename, int *nstars) {
+
+  int i, Ncol;
+  off_t Nrow;
+  char type[16];
+
+  StarPar_Stars *stars = NULL;
+
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  header.buffer = NULL;
+  matrix.buffer = NULL;
+  ftable.buffer = NULL;
+  theader.buffer = 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 header\n");
+    goto escape;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read matrix\n");
+    goto escape;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) goto escape;
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) goto escape;
+ 
+  GET_COLUMN(ra      , "RA"        ,   double);
+  GET_COLUMN(dec     , "DEC"       ,   double);
+  GET_COLUMN(glon    , "GLON"      ,   float);
+  GET_COLUMN(glat    , "GLAT"      ,   float);
+  GET_COLUMN(Ebv     , "Ebv"       ,   float);
+  GET_COLUMN(dEbv    , "dEbv"      ,   float);
+  GET_COLUMN(DistMag , "DistMag"   ,   float);
+  GET_COLUMN(dDistMag, "dDistMag"  ,   float);
+  GET_COLUMN(M_r     , "M_r"       ,   float);
+  GET_COLUMN(dM_r    , "dM_r"      ,   float);
+  GET_COLUMN(FeH     , "FeH"       ,   float);
+  GET_COLUMN(dFeH    , "dFeH"      ,   float);
+  GET_COLUMN(averef  , "averef"    ,   unsigned int);
+  GET_COLUMN(objID   , "objID"     ,   unsigned int);
+  GET_COLUMN(catID   , "catID"     ,   unsigned int);
+
+  gfits_free_header (&theader);
+  gfits_free_table  (&ftable);
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  ALLOCATE (stars, StarPar_Stars, Nrow);
+
+  for (i = 0; i < Nrow; i++) {
+    stars[i].R                = ra      [i];
+    stars[i].D	              = dec     [i];
+    stars[i].starpar.R        = ra      [i];
+    stars[i].starpar.D        = dec     [i];
+    stars[i].starpar.galLon   = glon    [i];
+    stars[i].starpar.galLat   = glat    [i];
+    stars[i].starpar.Ebv      = Ebv     [i];
+    stars[i].starpar.dEbv     = dEbv    [i];
+    stars[i].starpar.DistMag  = DistMag [i];
+    stars[i].starpar.dDistMag = dDistMag[i];
+    stars[i].starpar.M_r      = M_r     [i];
+    stars[i].starpar.dM_r     = dM_r    [i];
+    stars[i].starpar.FeH      = FeH     [i];
+    stars[i].starpar.dFeH     = dFeH    [i];
+    stars[i].starpar.averef   = averef  [i];
+    stars[i].starpar.objID    = objID   [i];
+    stars[i].starpar.catID    = catID   [i];
+  }
+
+  fclose (f);
+  *nstars = Nrow;
+  return stars;
+
+escape:
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table  (&ftable);
+
+  fclose (f);
+  return NULL;
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_make_subset.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_make_subset.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_make_subset.c	(revision 37567)
@@ -0,0 +1,44 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+// assign stars in the given region to the subset (NOTE: stars are sorted by RA, start is
+// first entry in stars array in this region)
+
+StarPar_Stars *loadstarpar_make_subset (StarPar_Stars *stars, int Nstars, int start, SkyRegion *region, int *nsubset) {
+
+  int i;
+
+  StarPar_Stars *subset = NULL;
+
+  // collect array of (Stars *) stars in a new output catalog
+  int Nsubset = 0;
+  int NSUBSET = 3000;
+  ALLOCATE (subset, StarPar_Stars, NSUBSET);
+
+  // find the rest of the stars in this output region
+  for (i = start; i < Nstars; i++) {
+    if (stars[i].flag) continue;
+
+    // check if in skyregion
+    if (stars[i].R < region[0].Rmin) continue;
+    if (stars[i].R > region[0].Rmax) break;
+    if (stars[i].D < region[0].Dmin) continue;
+    if (stars[i].D > region[0].Dmax) continue;
+	  
+    // check if in UserPatch (a GLOBAL)
+    if (stars[i].R < UserPatch.Rmin) continue;
+    if (stars[i].R > UserPatch.Rmax) break;
+    if (stars[i].D < UserPatch.Dmin) continue;
+    if (stars[i].D > UserPatch.Dmax) continue;
+	  
+    subset[Nsubset] = stars[i];
+    Nsubset ++;
+
+    stars[i].flag = TRUE;
+
+    CHECK_REALLOCATE (subset, StarPar_Stars, NSUBSET, Nsubset, 10000);
+  }
+
+  *nsubset = Nsubset;
+  return subset;
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_readstars.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_readstars.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_readstars.c	(revision 37567)
@@ -0,0 +1,164 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+# 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");
+
+StarPar_Stars *loadstarpar_readstars (char *filename, int *nstars) {
+
+  // read in the full FITS files ('cause I don't have a partial read option)
+  FILE *f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("can't read stellar parameter file: %s", filename);
+
+  int i, Ncol;
+  off_t Nrow;
+
+  Header header;
+  Matrix matrix;
+  Header theader;
+  FTable ftable;
+  
+  // 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)) {
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
+    fclose (f);
+    return (NULL);
+  }
+
+  char type[16];
+
+  GET_COLUMN (glat,    "l",    float);
+  GET_COLUMN (glon,    "b",    float);
+  GET_COLUMN (conv,    "conv", byte);
+  GET_COLUMN (lnZ,     "lnZ",  float);
+  GET_COLUMN (DistMag, "DM",   float);
+  GET_COLUMN (Ebv,     "EBV",  float);
+  GET_COLUMN (M_r,     "Mr",   float);
+  GET_COLUMN (FeH,     "FeH",  float);
+
+  // free the memory associated with the FITS files
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  // the next FITS extension contains the error information
+  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;
+  }
+  fclose (f);
+
+  double *errImage = (double *) matrix.buffer;
+
+  myAssert (Nrow == matrix.Naxis[2], "size mismatch?");
+
+  int NstarsIn = matrix.Naxis[2];
+
+  double Rmin = +360.0;
+  double Rmax = -360.0;
+  double Dmin = +360.0;
+  double Dmax = -360.0;
+
+  int Nstars = 0;
+  int NSTARS = 0.1*NstarsIn;
+
+  StarPar_Stars *stars = NULL;
+  ALLOCATE (stars, StarPar_Stars, NSTARS);
+
+  // libdvo uses Liu et al 2011 (A&A 526, A16) for default galactic coords,
+  // but Greg Green / LSD use the older Reid et al 2004 (ApJ 616, 872) definition
+  CoordTransform *transform = InitTransform (COORD_GALACTIC_REID_2004, COORD_CELESTIAL);
+
+  for (i = 0; i < NstarsIn; i++) {
+
+    // skip stars based on conv and lnZ
+    if (!conv[i]) continue;
+    if (lnZ[i] < -15.0) continue;
+
+    double R, D;
+    ApplyTransform (&R, &D, glon[i], glat[i], transform);
+
+    Rmin = MIN (Rmin, R);
+    Rmax = MAX (Rmax, R);
+    Dmin = MIN (Dmin, D);
+    Dmax = MAX (Dmax, D);
+
+    float dEbv     = 0.5*(errImage[i*20 + 5*0 + 3] - errImage[i*20 + 5*0 + 1]);
+    float dDistMag = 0.5*(errImage[i*20 + 5*1 + 3] - errImage[i*20 + 5*1 + 1]);
+    float dM_r     = 0.5*(errImage[i*20 + 5*2 + 3] - errImage[i*20 + 5*2 + 1]);
+    float dFeH     = 0.5*(errImage[i*20 + 5*3 + 3] - errImage[i*20 + 5*3 + 1]);
+
+    stars[Nstars].R = R;
+    stars[Nstars].D = D;
+    stars[Nstars].flag  = FALSE;
+    stars[Nstars].found = FALSE;
+
+    // NOTE that we have both stars.R,D and stars.starpar.R,D.  stars.R,D are used 
+    // here (in parallel with addstar) to locate the objects.  BUT, in the database,
+    // starpar.R,D is the authoratative position for the object (either that coming 
+    // from Greg / Eddie's table or that coming from the simulation)
+    stars[Nstars].starpar.R      = R;
+    stars[Nstars].starpar.D      = D;
+    stars[Nstars].starpar.galLon = glon[i];
+    stars[Nstars].starpar.galLat = glat[i];
+
+    stars[Nstars].starpar.Ebv      = Ebv[i]    ;
+    stars[Nstars].starpar.dEbv     = dEbv      ;
+    stars[Nstars].starpar.DistMag  = DistMag[i];
+    stars[Nstars].starpar.dDistMag = dDistMag  ;
+    stars[Nstars].starpar.M_r      = M_r[i]    ;
+    stars[Nstars].starpar.dM_r     = dM_r      ;
+    stars[Nstars].starpar.FeH      = FeH[i]    ;
+    stars[Nstars].starpar.dFeH     = dFeH      ;
+
+    Nstars ++;
+
+    CHECK_REALLOCATE (stars, StarPar_Stars, NSTARS, Nstars, 10000);
+  }
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  *nstars = Nstars;
+  return (stars);
+}
+
+int loadstarpar_sortStars (StarPar_Stars *stars, int Nstars) {
+
+# define SWAPFUNC(A,B){ StarPar_Stars temp = stars[A]; stars[A] = stars[B]; stars[B] = temp; }
+# define COMPARE(A,B)(stars[A].R < stars[B].R)
+
+  OHANA_SORT (Nstars, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+  
+  return TRUE;
+}
+
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_remote_hosts.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_remote_hosts.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_remote_hosts.c	(revision 37567)
@@ -0,0 +1,141 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+# include <sys/types.h>
+# include <sys/wait.h>
+
+# define DEBUG 1
+
+// we are running N parallel remote jobs on the remote hosts.  In the usual remote
+// processing (eg, relphot or relastro), we launch one job per remote host.  In this case,
+// we are launching one job foreach table (catalog.cpt) being touched.  individual hosts
+// may have more than one job active at a time.  
+
+int       Nhosts = 0;
+HostInfo **hosts = NULL;
+
+int init_remote_hosts () {
+
+  Nhosts = 10;
+  ALLOCATE (hosts, HostInfo *, Nhosts);
+
+  int i;
+  for (i = 0; i < Nhosts; i++) {
+    hosts[i] = NULL;
+  }
+  return TRUE;
+}
+
+int find_empty_slot () {
+
+  int i;
+  for (i = 0; i < Nhosts; i++) {
+    if (hosts[i] == NULL) return i;
+  }
+  return -1;
+}
+
+int harvest_all () {
+
+  int slot = -1;
+
+  while (slot != -2) {
+    slot = harvest_host ();
+    usleep (50000);
+  }
+  return TRUE;
+}
+ 
+// put the host in the list in a free slot. NOTE: this should never be called if we do not
+// already have a free slot.
+int save_remote_host (HostInfo *host) {
+
+  int i;
+  for (i = 0; i < Nhosts; i++) {
+    if (hosts[i] == NULL) {
+      hosts[i] = host;
+      return TRUE;
+    }
+  }
+  myAbort ("failed to find an empty slot: this is a programming error");
+  return FALSE;
+}
+
+// wait for all children to complete, report output to stdout
+// possible states when function is finished:
+// * no child was harvested, but children still exist
+// * no outstanding children
+// * a child was harvested
+int harvest_host () {
+
+  // check if any children have finished...
+  int status = 0;
+  int pid = waitpid (-1, &status, WNOHANG);
+
+  if (!pid) return -1; // there are outstanding children, but none have exited, no slot was opened
+  if ((pid == -1) && (errno == ECHILD)) return -2; // there are no outstanding children
+  if ((pid == -1) && (errno != ECHILD)) myAbort ("programming error?");
+
+  // find the host which has finished
+  int i;
+  int found = FALSE;
+  for (i = 0; (i < Nhosts) && !found; i++) {
+    if (!hosts[i]) continue; // unassigned slot
+    if (hosts[i][0].pid != pid) continue;
+    found = TRUE;
+  }
+  myAssert (found, "Programming error: failed to matched finished job to known host!");
+  int slot = i;
+
+  HostInfo *host = hosts[slot];
+
+  // check on the status of this job and report any output
+  if (DEBUG) fprintf (stdout, "job finished for %s (%d)\n", host->hostname, pid);
+
+  int Nout, printHead;
+
+  // read stdout
+  EmptyIOBuffer (&host->stdout, 100, host->stdio[HOST_STDOUT]);
+  printHead = VERBOSE || (host->stdout.Nbuffer > 0);
+  if (printHead) fprintf (stdout, "--- stdout from %s --- (%d bytes, v2)\n", host->hostname, host->stdout.Nbuffer);
+  Nout = write (STDOUT_FILENO, host->stdout.buffer, host->stdout.Nbuffer);
+  if (Nout != host->stdout.Nbuffer) { fprintf (stderr, "(error writing log?)\n"); }
+  FlushIOBuffer (&host->stdout);
+  if (printHead) fprintf (stdout, "\n");
+	    
+  // read stderr
+  EmptyIOBuffer (&host->stderr, 100, host->stdio[HOST_STDERR]);
+  printHead = VERBOSE || (host->stderr.Nbuffer > 0);
+  if (printHead) fprintf (stdout, "--- stderr from %s --- (%d bytes, v2)\n", host->hostname, host->stderr.Nbuffer);
+  Nout = write (STDOUT_FILENO, host->stderr.buffer, host->stderr.Nbuffer);
+  if (Nout != host->stderr.Nbuffer) { fprintf (stderr, "(error writing log?)\n"); }
+  FlushIOBuffer (&host->stderr);
+  if (printHead) fprintf (stdout, "\n");
+
+  if (WIFEXITED(status)) {
+    if (DEBUG) fprintf (stdout, "normal completion, exit status is %d\n", WEXITSTATUS(status));
+    host->status = WEXITSTATUS(status);
+    if (host->status) {
+      fprintf (stdout, "job failed on %s\n", host->hostname);
+    }
+  } else {
+    host->status = -1;
+    fprintf (stdout, "job exited abnormally on %s\n", host->hostname);
+  }
+
+  // close opened connections
+  close (host->stdio[HOST_STDIN]);
+  close (host->stdio[HOST_STDOUT]);
+  close (host->stdio[HOST_STDERR]);
+
+  // free data associated with the host
+  free (host->hostname);
+  free (host->pathname);
+  FreeIOBuffer (&host->stdout);
+  FreeIOBuffer (&host->stderr);
+  free (host);
+
+  // free the slot
+  hosts[slot] = NULL;
+  return slot; 
+}
+
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_save_remote.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_save_remote.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_save_remote.c	(revision 37567)
@@ -0,0 +1,84 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+# define DEBUG 1
+
+int strextend (char *input, char *format,...) {
+
+  char tmpextra[1024], tmpline[1024];
+  va_list argp;
+
+  va_start (argp, format);
+  vsnprintf (tmpextra, 1024, format, argp);
+  snprintf (tmpline, 1024, "%s %s", input, tmpextra);
+  strcpy (input, tmpline);
+
+  return TRUE;
+}
+
+int loadstarpar_save_remote (StarPar_Stars *stars, int Nstars, HostTable *hosts, SkyRegion *region, char *fullname, AddstarClientOptions *options) {
+
+  char uniquer[12];
+  int TIME = time(NULL);
+  int PID = getpid();
+  snprintf (uniquer, 12, "%05d.%05d", PID, TIME % 100000);
+
+  // if this region is a parallel thing, save and launch remote
+  if (!PARALLEL) { 
+    loadstarpar_catalog (stars, Nstars, region, fullname, options);
+  } else {
+    int N = hosts->index[region->hostID];
+    HostInfo *hostMach = &hosts->hosts[N];
+
+    // save to a unique filename
+    char filename[1024]; // CATDIR/tmpdir/starpar.PID.index.fits
+    snprintf (filename, 1024, "%s/tmpdir/starpar.%s.%05d.fits", CATDIR, uniquer, region->index);
+
+    // write the data to the given FITS file
+    loadstarpar_save_stars (filename, stars, Nstars);
+
+    int slot = -1;
+    while (slot == -1) {
+      slot = find_empty_slot ();
+      if (slot == -1) {
+	usleep (50000);
+	slot = harvest_host();
+	myAssert (slot != -2, "we should not call harvest_host here if we have open slots");
+      }
+    }
+
+    // allocate a host for this job
+    HostInfo *host = NULL;
+    ALLOCATE (host, HostInfo, 1);
+
+    // we want to run this job on the host described by hostMach.  copy
+    // immutable data from hostMach to a locally allocated host:
+    host->hostID = hostMach->hostID;
+    host->hostname = strcreate (hostMach->hostname);
+    host->pathname = strcreate (hostMach->pathname);
+    InitIOBuffer (&host->stdout, 1000);
+    InitIOBuffer (&host->stderr, 1000);
+
+    // got a valid slot, so launch a new host
+
+    // need to generate the remote command
+    char command[1024];
+    snprintf (command, 1024, "loadstarpar_client");
+    strextend (command, "-hostID %d", host->hostID);
+    strextend (command, "-D CATDIR %s", CATDIR);
+    strextend (command, "-hostdir %s", host->pathname);
+    strextend (command, "-cpt %s", region->name);
+    strextend (command, "-input %s", filename);
+
+    // launch the job on the remote machine (no handshake)
+    int errorInfo = 0;
+    int pid = rconnect ("ssh", host->hostname, command, host->stdio, &errorInfo, FALSE);
+    if (!pid) {
+      if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", host->hostname, errorInfo);
+      exit (1);
+    }
+    host->pid = pid; // save for future reference
+    
+    save_remote_host (host);
+  }
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_table.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_table.c	(revision 37567)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/addstar/src/loadICRF_table.c	(revision 37567)
@@ -0,0 +1,50 @@
+# include "addstar.h"
+# include "loadstarpar.h"
+
+# 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");
+
+int loadstarpar_table (SkyList *skylistInput, HostTable *hosts, char *filename, AddstarClientOptions *options) {
+  
+  int i, Nstars;
+
+  StarPar_Stars *stars = loadstarpar_readstars (filename, &Nstars);
+
+  // sort the stars by RA
+  loadstarpar_sortStars (stars, Nstars);
+
+  // scan through the stars, loading the containing catalogs
+  // skip through table for unsaved stars
+  for (i = 0; i < Nstars; i++) {
+    if (stars[i].flag) continue;
+
+    // scan forward until we read the UserPatch
+    if (stars[i].R < UserPatch.Rmin) continue;
+    if (stars[i].R > UserPatch.Rmax) break;
+    if (stars[i].D < UserPatch.Dmin) continue;
+    if (stars[i].D > UserPatch.Dmax) continue;
+
+    // identify the relevant catalog
+    SkyList *skylist = SkyRegionByPoint_List (skylistInput, -1, stars[i].R, stars[i].D);
+    if (skylist[0].Nregions == 0) {
+      SkyListFree (skylist);
+      continue;
+    }
+    SkyRegion *region = skylist[0].regions[0];
+
+    // select stars matching this region
+    int Nsubset;
+    StarPar_Stars *subset = loadstarpar_make_subset (stars, Nstars, i, region, &Nsubset);
+
+    // In parallel mode, write out the subset to a disk file.  Block until a remote host
+    // is available.  In serial mode, just match against the appropriate region and save
+    loadstarpar_save_remote (subset, Nsubset, hosts, region, skylist[0].filename[0], options);
+  }
+
+  // wait for last remote clients to finish
+  harvest_all ();
+
+  return TRUE;
+}
+
