Index: trunk/Ohana/src/opihi/cmd.astro/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/Makefile	(revision 35263)
+++ trunk/Ohana/src/opihi/cmd.astro/Makefile	(revision 35416)
@@ -30,4 +30,5 @@
 $(SRC)/drizzle.$(ARCH).o	   \
 $(SRC)/flux.$(ARCH).o		   \
+$(SRC)/fitplx.$(ARCH).o	   \
 $(SRC)/fixwrap.$(ARCH).o	   \
 $(SRC)/fixcols.$(ARCH).o	   \
Index: trunk/Ohana/src/opihi/cmd.astro/fitplx.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/fitplx.c	(revision 35416)
+++ trunk/Ohana/src/opihi/cmd.astro/fitplx.c	(revision 35416)
@@ -0,0 +1,335 @@
+# include "astro.h"
+# define J2000 51544.5       /* Modified Julian date at standard epoch J2000 */
+
+# define ESCAPE(MSG,...) {			\
+    gprint (GP_ERR, MSG, __VA_ARGS__);		\
+    return FALSE; }
+
+typedef struct {
+  double Ro, dRo;
+  double Do, dDo;
+
+  double uR, duR;
+  double uD, duD;
+
+  double p, dp;
+
+  double chisq;
+  int Nfit;
+} PlxFit;
+
+int FitPMandPar (PlxFit *fit, double *X, double *dX, double *Y, double *dY, double *T, double *pR, double *pD, int Npts, int VERBOSE);
+int sun_ecliptic (double mjd, double *lambda, double *beta, double *epsilon, double *Radius);
+int ParFactor (double *pR, double *pD, double RA, double DEC, double Time);
+
+int fitplx (int argc, char **argv) {
+  
+  int i, N;
+
+  Vector *rvec, *dvec, *tvec, *dRvec, *dDvec;
+
+  Vector *mvec = NULL; // mask vector
+  if ((N = get_argument (argc, argv, "-mask"))) {
+    remove_argument (N, &argc, argv);
+    if ((mvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    CastVector (mvec, OPIHI_INT);
+  }
+
+  int VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    VERBOSE = TRUE;
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: fitplx (ra) (dR) (dec) (dD) (mjd) [-mask mask]\n");
+    // what about the errors?
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  // if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  // Nx = buf[0].header.Naxis[0];
+  // Ny = buf[0].header.Naxis[1];
+  
+  if ((rvec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) ESCAPE ("missing vector %s\n", argv[1]);
+  if ((dvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) ESCAPE ("missing vector %s\n", argv[3]);
+  if ((tvec = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) ESCAPE ("missing vector %s\n", argv[5]);
+
+  if ((dRvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) ESCAPE ("missing vector %s\n", argv[2]);
+  if ((dDvec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) ESCAPE ("missing vector %s\n", argv[4]);
+
+  double *R = rvec->elements.Flt;
+  double *D = dvec->elements.Flt;
+  double *T = tvec->elements.Flt;
+  
+  double *dR = dRvec->elements.Flt;
+  double *dD = dDvec->elements.Flt;
+
+  int *mask = NULL;
+  if (mvec) {
+    mask = mvec->elements.Int;
+  }
+
+  N = tvec->Nelements; // XXX check other lengths
+
+  // find mean values to remove
+  double Npts = 0;
+  double Tmean = 0;
+  double Rmean = 0;
+  double Dmean = 0;
+  double Tmin = +1000000;
+  double Tmax = -1000000;
+  for (i = 0; i < N; i++) {
+    if (mask && !mask[i]) continue;
+    Rmean += R[i];
+    Dmean += D[i];
+    Tmean += T[i];
+    Tmin = MIN(Tmin, T[i]);
+    Tmax = MAX(Tmax, T[i]);
+    Npts += 1.0;
+  }
+  Rmean /= Npts;
+  Dmean /= Npts;
+  Tmean /= Npts;
+
+  float Trange = Tmax - Tmin;
+  // fprintf (stderr, "R,D : %f,%f, T: %f, Trange: %f, Tmin: %f, Tmax: %f\n", Rmean, Dmean, Tmean, Trange, Tmin, Tmax);
+
+  /* project coordinates to a plane centered on the object with units of arcsec */
+  Coords coords;
+  coords.crval1 = Rmean;
+  coords.crval2 = Dmean;
+  coords.crpix1 = 0;
+  coords.crpix2 = 0;
+  coords.cdelt1 = coords.cdelt2 = 1.0 / 3600.0;
+  coords.pc1_1  = coords.pc2_2 = 1.0;
+  coords.pc1_2  = coords.pc2_1 = 0.0;
+  coords.Npolyterms = 1;
+  strcpy (coords.ctype, "RA---SIN");
+
+  double *X, *Y, *t, *pX, *pY, *dX, *dY;
+  ALLOCATE (X, double, N);
+  ALLOCATE (Y, double, N);
+  ALLOCATE (dX, double, N);
+  ALLOCATE (dY, double, N);
+  ALLOCATE (t, double, N);
+  ALLOCATE (pX, double, N);
+  ALLOCATE (pY, double, N);
+
+  float pXmin = +2.0;
+  float pXmax = -2.0;
+  float pYmin = +2.0;
+  float pYmax = -2.0;
+
+  int n = 0;
+  for (i = 0; i < N; i++) {
+    if (mask && !mask[i]) continue;
+    RD_to_XY (&X[n], &Y[n], R[i], D[i], &coords);
+    dX[n] = dR[i];
+    dY[n] = dD[i];
+    t[n] = (T[i] - Tmean) / 365.25;
+    ParFactor (&pX[n], &pY[n], R[i], D[i], T[i]);
+    pXmin = MIN (pXmin, pX[n]);
+    pXmax = MAX (pXmax, pX[n]);
+    pYmin = MIN (pYmin, pY[n]);
+    pYmax = MAX (pYmax, pY[n]);
+    n++;
+  }
+  float dXRange = pXmax - pXmin;
+  float dYRange = pYmax - pYmin;
+  float parRange = hypot (dXRange, dYRange);
+	
+  // fprintf (stderr, "par factor range: %f\n", parRange);
+
+  PlxFit fit;
+  FitPMandPar (&fit, X, dX, Y, dY, t, pX, pY, n, VERBOSE);
+
+  // fprintf (stderr, "Roff, Doff: %f, %f; dRo, dDo: %f, %f\n", fit.Ro, fit.Do, fit.dRo, fit.dDo);
+  
+  XY_to_RD (&Rmean, &Dmean, fit.Ro, fit.Do, &coords);
+  if (VERBOSE) {
+    fprintf (stderr, "Ro, Do: %f, %f +/- %f, %f\n", Rmean, Dmean, fit.dRo, fit.dDo);
+    fprintf (stderr, "uR, uD: %f, %f; duR, duD: %f, %f\n", fit.uR, fit.uD, fit.duR, fit.duD);
+    fprintf (stderr, "par: %f +/- %f\n", fit.p, fit.dp);
+    fprintf (stderr, "chisq: %f Nfit %d\n", fit.chisq, fit.Nfit);
+  }
+
+  set_variable ("RA",   Rmean);
+  set_variable ("DEC",  Dmean);
+  set_variable ("dR",   fit.dRo);
+  set_variable ("dD",   fit.dDo);
+  set_variable ("uR",   fit.uR);
+  set_variable ("uD",   fit.uD);
+  set_variable ("duR",   fit.duR);
+  set_variable ("duD",   fit.duD);
+  set_variable ("plx",  fit.p);
+  set_variable ("dplx", fit.dp);
+  
+  set_variable ("Tmean",  Tmean);
+  set_variable ("Trange", Trange);
+  set_variable ("Prange", parRange);
+
+  set_variable ("chisq", fit.chisq);
+  set_variable ("Nfit",  fit.Nfit);
+
+  return (TRUE);
+}
+
+/* do we want an init function which does the alloc and a clear function to free? */
+int FitPMandPar (PlxFit *fit, double *X, double *dX, double *Y, double *dY, double *T, double *pR, double *pD, int Npts, int VERBOSE) {
+
+  int i;
+
+  static double **A = NULL;
+  static double **B = NULL;
+  double wx, wy, Wx, Wy, Tx, Ty, Tx2, Ty2, Xs, Ys, XT, YT;
+  double PR, PD, PRT, PDT, PRX, PDY, PR2, PD2;
+  double chisq, Xf, Yf;
+
+  if (A == NULL) {
+    ALLOCATE (A, double *, 5);
+    ALLOCATE (B, double *, 5);
+    for (i = 0; i < 5; i++) {
+      ALLOCATE (A[i], double, 5);
+      ALLOCATE (B[i], double, 1);
+      memset (A[i], 0, 5*sizeof(double));
+      memset (B[i], 0, 1*sizeof(double));
+    }
+  }
+
+  PR = PD = PRT = PDT = PRX = PDY = PR2 = PD2 = 0.0;
+  Wx = Wy = Tx = Ty = Tx2 = Ty2 = Xs = Ys = XT = YT = 0.0;
+  for (i = 0; i < Npts; i++) {
+
+    if (VERBOSE) fprintf (stderr, "%f %f : %f %f : %f : %f %f\n", X[i], dX[i], Y[i], dY[i], T[i], pR[i], pD[i]);
+
+    /* handle case where dX or dY = 0.0 */
+    wx = 1.0 / SQ(dX[i]);
+    wy = 1.0 / SQ(dY[i]);
+
+    Wx += wx;
+    Wy += wy;
+
+    Tx += T[i]*wx;
+    Ty += T[i]*wy;
+    
+    Tx2 += SQ(T[i])*wx;
+    Ty2 += SQ(T[i])*wy;
+    
+    PR += pR[i]*wx;
+    PD += pD[i]*wy;
+    
+    PRT += pR[i]*T[i]*wx;
+    PDT += pD[i]*T[i]*wy;
+    
+    PRX += pR[i]*X[i]*wx;
+    PDY += pD[i]*Y[i]*wy;
+    
+    PR2 += SQ(pR[i])*wx;
+    PD2 += SQ(pD[i])*wy;
+
+    Xs += X[i]*wx;
+    Ys += Y[i]*wy;
+
+    XT += X[i]*T[i]*wx;
+    YT += Y[i]*T[i]*wy;
+  }
+
+  A[0][0] = Wx;
+  A[0][1] = Tx;
+  A[0][4] = PR;
+
+  A[1][0] = Tx;
+  A[1][1] = Tx2;
+  A[1][4] = PRT;
+
+  A[2][2] = Wy;
+  A[2][3] = Ty;
+  A[2][4] = PD;
+
+  A[3][2] = Ty;
+  A[3][3] = Ty2;
+  A[3][4] = PDT;
+
+  A[4][0] = PR;
+  A[4][1] = PRT;
+  A[4][2] = PD;
+  A[4][3] = PDT;
+  A[4][4] = PR2 + PD2;
+
+  B[0][0] = Xs;
+  B[1][0] = XT;
+  B[2][0] = Ys;
+  B[3][0] = YT;
+  B[4][0] = PRX + PDY;
+
+  dgaussjordan ((double **)A, (double **)B, 5, 1);
+
+  fit[0].Ro = B[0][0];
+  fit[0].uR = B[1][0];
+  fit[0].Do = B[2][0];
+  fit[0].uD = B[3][0];
+  fit[0].p  = B[4][0];
+  
+  fit[0].dRo = sqrt(A[0][0]);
+  fit[0].duR = sqrt(A[1][1]);
+  fit[0].dDo = sqrt(A[2][2]);
+  fit[0].duD = sqrt(A[3][3]);
+  fit[0].dp  = sqrt(A[4][4]);
+  
+  // add up the chi square for the fit
+  chisq = 0.0;
+  for (i = 0; i < Npts; i++) {
+    Xf = fit[0].Ro + fit[0].uR*T[i] + fit[0].p*pR[i];
+    Yf = fit[0].Do + fit[0].uD*T[i] + fit[0].p*pD[i];
+    chisq += SQ(X[i] - Xf) / SQ(dX[i]);
+    chisq += SQ(Y[i] - Yf) / SQ(dY[i]);
+    if (VERBOSE) fprintf (stderr, "chisq contrib : %f %f : %f %f : %f %f : %f %f : %f\n", Xf, Yf, X[i] - Xf, Y[i] - Yf, dX[i], dY[i], (X[i] - Xf) / dX[i], (Y[i] - Yf) / dY[i], chisq);
+  }
+  fit[0].Nfit = Npts;
+
+  // the reduced chisq is divided by (Ndof = 2*Npts - 5)
+  fit[0].chisq = chisq / (2.0*Npts - 5.0);
+  return (TRUE);
+}
+
+/* Low precision formulae for the sun, from Astro. Almanac p. C5 (2012) */
+int sun_ecliptic (double mjd, double *lambda, double *beta, double *epsilon, double *Radius) {
+
+  double n = mjd - J2000;                          // day number relative to standard epoch
+  double L = 280.460 + 0.9856474 * n;	           // mean solar longitute (corr. for aberration)
+  double g = (357.528 + 0.9856003 * n)*RAD_DEG;    // Mean anomaly
+
+  *lambda = L + 1.915 * sin(g) + 0.020 * sin(2*g); // solar longitude in degrees
+  *beta = 0.0;					   // approx latitude
+  *epsilon = (23.439 - 0.0000004 * n);		   // obliquity of ecliptic in degrees
+  *Radius = 1.00014 - 0.01671*cos(g) - 0.00014*cos(2*g); // earth-to-sun dist in AU
+  return TRUE;
+}
+
+/* given RA, DEC, Time, calculate the parallax factor */
+// RA,DEC are decimal degrees
+// Time is MJD
+int ParFactor (double *pR, double *pD, double RA, double DEC, double Time) {
+
+  double lambda, beta, epsilon, Radius;
+
+  // Time must be mjd
+  sun_ecliptic (Time, &lambda, &beta, &epsilon, &Radius);
+
+  double lambda_rad = lambda*RAD_DEG;
+  double epsilon_rad = epsilon*RAD_DEG;
+  double RA_rad = RA*RAD_DEG;
+  double DEC_rad = DEC*RAD_DEG;
+
+  double x = Radius*cos(lambda_rad);
+  double y = Radius*cos(epsilon_rad)*sin(lambda_rad);
+  double z = Radius*sin(epsilon_rad)*sin(lambda_rad);
+
+  *pR = +(y*cos(RA_rad) - x*sin(RA_rad));
+  *pD = -(y*sin(RA_rad) + x*cos(RA_rad))*sin(DEC_rad) + z*cos(DEC_rad);
+
+  return TRUE;
+}
Index: trunk/Ohana/src/opihi/cmd.astro/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/init.c	(revision 35263)
+++ trunk/Ohana/src/opihi/cmd.astro/init.c	(revision 35416)
@@ -14,4 +14,5 @@
 int drizzle                 PROTO((int, char **));
 int flux                    PROTO((int, char **));
+int fitplx                  PROTO((int, char **));
 int fixwrap                 PROTO((int, char **));
 int fiximage                PROTO((int, char **));
@@ -71,4 +72,5 @@
   {1, "drizzle",     drizzle,      "transform image to image"},
   {1, "flux",        flux,         "flux in a convex contour"},
+  {1, "fitplx",      fitplx,       "fit proper motion and parallax"},
   {1, "fixwrap",     fixwrap,      "fix megacam over-wrapped pixels"},
   {1, "fiximage",    fiximage,     "fix pixels in an image by interpolation"},
Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 35263)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 35416)
@@ -150,4 +150,5 @@
 $(SRC)/vsmooth.$(ARCH).o	   \
 $(SRC)/vstats.$(ARCH).o		   \
+$(SRC)/xsection.$(ARCH).o          \
 $(SRC)/wd.$(ARCH).o		   \
 $(SRC)/write_vectors.$(ARCH).o	   \
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 35263)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 35416)
@@ -141,4 +141,5 @@
 int wd               PROTO((int, char **));
 int write_vectors    PROTO((int, char **));
+int xsection         PROTO((int, char **));
 int zap              PROTO((int, char **));
 int zplot            PROTO((int, char **));
@@ -299,4 +300,5 @@
   {1, "wd",           wd,               "write an image to a file"},
   {1, "write",        write_vectors,    "write vectors to datafile"},
+  {1, "xsection",     xsection,         "generate cross-section histogram for an image (or region)"},
   {1, "zap",          zap,              "assign values to pixel regions"},
   {1, "zplot",        zplot,            "plot x y with size scaled by z"},
Index: trunk/Ohana/src/opihi/cmd.data/xsection.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/xsection.c	(revision 35416)
+++ trunk/Ohana/src/opihi/cmd.data/xsection.c	(revision 35416)
@@ -0,0 +1,109 @@
+# include "data.h"
+
+// take an image and accumulate a histogram in some direction
+int xsection (int argc, char **argv) {
+  
+  int i, j, N, Nbins;
+  int sx, sy, nx, ny, bin;
+  int *vecN;
+  float *V, delta;
+  Vector *vec1, *vec2;
+  Buffer *buf;
+
+ // int Quiet = FALSE;
+ // if ((N = get_argument (argc, argv, "-q"))) {
+ //   Quiet = TRUE;
+ //   remove_argument (N, &argc, argv);
+ // }
+ // if ((N = get_argument (argc, argv, "-quiet"))) {
+ //   Quiet = TRUE;
+ //   remove_argument (N, &argc, argv);
+ // }
+
+  delta = 1.0;
+  if ((N = get_argument (argc, argv, "-delta"))) {
+    remove_argument (N, &argc, argv);
+    delta = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  sx = sy = 0.0;
+  nx = ny = 0.0;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    sx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    sy = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    nx = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    ny = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: xsection <buffer> <x> <y> (angle) [-region sx sy nx ny] [-delta binsize]\n");
+    return (FALSE);
+  }
+
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  
+  int Nx = buf[0].matrix.Naxis[0];
+  int Ny = buf[0].matrix.Naxis[1];
+
+  /* if either range is set to zero, use the rest of the chip */
+  if (nx == 0) nx = Nx - sx;
+  if (ny == 0) ny = Ny - sy;
+
+  if ((sx < 0) || (sy < 0) || (sx+nx > Nx) || (sy+ny > Ny)) {
+    gprint (GP_ERR, "region out of range\n");
+    return (FALSE);
+  }
+
+
+  // center coords are center of the region
+  float Xo = sx + 0.5*nx;
+  float Yo = sy + 0.5*ny;
+
+  float angle = atof(argv[4]);
+  float secant = MAX(2.0*fabs(cos(angle*RAD_DEG)/Nx), 2.0*fabs(sin(angle*RAD_DEG)/Ny));
+  float range = 1.1 / secant;
+
+  Nbins = 2*range / delta;
+
+  if ((vec1 = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vec2 = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  ResetVector (vec1, OPIHI_FLT, Nbins + 1);
+  ResetVector (vec2, OPIHI_FLT, Nbins + 1);
+  bzero (vec1[0].elements.Flt, vec1[0].Nelements*sizeof(opihi_flt));
+  bzero (vec2[0].elements.Flt, vec2[0].Nelements*sizeof(opihi_flt));
+  
+  V = (float *)buf[0].matrix.buffer;
+
+  float dx = cos(angle*RAD_DEG);
+  float dy = sin(angle*RAD_DEG);
+
+  ALLOCATE (vecN, int, Nbins + 1);
+  memset (vecN, 0, (Nbins + 1)*sizeof(int));
+
+  for (j = sy; j < sy + ny; j++) {
+    float dY = (j - Yo);
+    for (i = sx; i < sx + nx; i++) {
+      float value = V[i*Nx + j];
+      if (!isfinite(value)) continue;
+      float dX = (i - Xo);
+      float L = (dX * dx) + (dY * dy);
+      bin = MAX (MIN (Nbins, (L / delta) + 0.5*Nbins), 0);
+      vec2[0].elements.Flt[bin] += value;
+      vecN[bin] ++;
+    }
+  }
+  for (i = 0; i < Nbins + 1; i++) {
+    vec1[0].elements.Flt[i] = (i - 0.5*Nbins)*delta;
+    vec2[0].elements.Flt[i] /= (float) vecN[i];
+  }
+  
+  return (TRUE);
+}
+
Index: trunk/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/avextract.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/avextract.c	(revision 35416)
@@ -137,5 +137,5 @@
   // this does all the work of re-packaging the command, calling it on the remote machines, then loading in the results
   if (PARALLEL && !HOST_ID) {
-    int status = HostTableParallelOps (argc, argv, RESULT_FILE, TRUE, 0, VERBOSE);
+      int status = HostTableParallelOps (skylist, argc, argv, RESULT_FILE, TRUE, 0, VERBOSE);
 
     dbFreeFields (fields, Nfields);
Index: trunk/Ohana/src/opihi/dvo/avmatch.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 35416)
@@ -95,5 +95,5 @@
 
     // I need to pass the RA & DEC vectors to the remote clients...
-    int status = HostTableParallelOps (argc, argv, RESULT_FILE, TRUE, RAvec->Nelements, VERBOSE);
+    int status = HostTableParallelOps (skylist, argc, argv, RESULT_FILE, TRUE, RAvec->Nelements, VERBOSE);
     if (vec) free (vec);
     
Index: trunk/Ohana/src/opihi/dvo/dvo_host_utils.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/dvo_host_utils.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/dvo_host_utils.c	(revision 35416)
@@ -8,5 +8,5 @@
 # define DIE(WHO,MSG) { perror(WHO); myAbort(MSG); }
 
-int HostTableLaunchJobs (HostTable *table, char *basecmd, char *options, int VERBOSE) {
+int HostTableLaunchJobs (SkyList *sky, HostTable *table, char *basecmd, char *options, int VERBOSE) {
 
   char uniquer[12];
@@ -35,6 +35,22 @@
 
   int top_status = TRUE;
-  int i;
+  int i, j;
   for (i = 0; i < table->Nhosts; i++) {
+
+      if (sky && (sky->Nregions < table->Nhosts)) {
+      // do any of the regions want this host?
+      int wantThisHost = FALSE;
+      for (j = 0; j < sky->Nregions; j++) {
+	if (HostTableTestHost (sky->regions[j], table->hosts[i].hostID)) {
+	  wantThisHost = TRUE;
+	  break;
+	}
+      }
+      if (!wantThisHost) {
+	// fprintf (stderr, "skip host %s\n", table->hosts[i].hostname);
+	continue;
+      }
+      // fprintf (stderr, "not skip host %s\n", table->hosts[i].hostname);
+    }
 
     // ensure that the paths are absolute path names
@@ -88,14 +104,14 @@
 // an alternative ending step ignores the result files and instead saves the names into
 // the list 'result:n' for the user to access as desired
-int HostTableParallelOps (int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE) {
+int HostTableParallelOps (SkyList *sky, int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE) {
 
   int i;
 
-  // load the list of hosts
-  SkyTable *sky = GetSkyTable();
-  if (!sky) {
-    gprint (GP_ERR, "failed to load sky table for database\n");
-    return FALSE;
-  }
+  // XX // load the list of hosts
+  // XX SkyTable *sky = GetSkyTable();
+  // XX if (!sky) {
+  // XX   gprint (GP_ERR, "failed to load sky table for database\n");
+  // XX   return FALSE;
+  // XX }
 
   char *tmppath = GetCATDIR ();
@@ -145,5 +161,5 @@
 
   // launch this command remotely
-  HostTableLaunchJobs (table, basecmd, options, VERBOSE);
+  HostTableLaunchJobs (sky, table, basecmd, options, VERBOSE);
   free (options);
   free (basecmd);
@@ -183,4 +199,5 @@
 
     if (table->hosts[i].status) continue; 
+    if (!table->hosts[i].pid) continue;
 
     if (ReadVectors) {
Index: trunk/Ohana/src/opihi/dvo/mextract.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/mextract.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/mextract.c	(revision 35416)
@@ -16,5 +16,5 @@
     if (field->ID == MEAS_CENTER_OFFSET)  return TRUE; // 0.5*NX, 0.5*NY
     if (field->ID == MEAS_EXPNAME_AS_INT) return TRUE; // expname (or as int)
-    if (field->ID == MEAS_AIRMASS)        return TRUE; // airmass
+    if (field->ID == MEAS_MEAN_AIRMASS)   return TRUE; // airmass
     return FALSE;
 }
@@ -171,5 +171,5 @@
 
     // call the remote client
-    int status = HostTableParallelOps (targc, targv, RESULT_FILE, TRUE, 0, VERBOSE);
+    int status = HostTableParallelOps (skylist, targc, targv, RESULT_FILE, TRUE, 0, VERBOSE);
 
     dbFreeFields (fields, Nfields);
Index: trunk/Ohana/src/opihi/dvo/mmatch.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/mmatch.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/mmatch.c	(revision 35416)
@@ -106,76 +106,4 @@
   RAvec  = NULL;
   DECvec = NULL;
-  if (PARALLEL && !HOST_ID) {
-
-    // We need to copy the args to a temp array and modify them so that we send the
-    // correct set to the remote client.  The args list looks like this:
-    // if (!CoordsFile) : mmatch (RA) (DEC) (RADIUS) field, ...
-    // if ( CoordsFile) : mmatch (RADIUS) field, ... [because we stripped off the -coords filename elements]
-
-    // allocate the temp array and copy all but (RA) (DEC)
-    int targc = 0;
-    char **targv = NULL;
-    ALLOCATE (targv, char *, argc + 2);
-    for (i = 0; i < argc; i++) {
-      if (!CoordsFile && (i == 1)) continue;
-      if (!CoordsFile && (i == 2)) continue;
-      targv[targc] = strcreate (argv[i]);
-      targc ++;
-    }
-
-    // if not specified, create the coords.fits input file
-    if (!CoordsFile) {
-      // get vectors corresponding to coordinates of interest
-      if ((RAvec  = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto help;
-      if ((DECvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) goto help;
-      
-      ALLOCATE (vec, Vector *, 2);
-      vec[0] = RAvec;
-      vec[1] = DECvec;
-
-      CoordsFile = abspath("coords.fits", 1024);
-      int status = WriteVectorTableFITS (CoordsFile, "COORDS", vec, 2, FALSE, NULL);
-      if (!status) goto escape;
-    }
-
-    // add the coords file to the args list
-    targv[targc+0] = strcreate ("-coords");
-    targv[targc+1] = CoordsFile; // this gets freed with targv
-    targc += 2;
-    
-    // if needed, add the index vector to the args list
-    if (IDXvec) {
-      REALLOCATE (targv, char *, targc + 2);
-      targv[targc+0] = strcreate ("-index");
-      targv[targc+1] = strcreate (IDXvec[0].name);
-      targc += 2;
-    }      
-
-    if (loadImages) {
-      Image *image;
-      off_t Nimage;
-      if ((image = LoadImagesDVO (&Nimage)) == NULL) goto escape;
-
-      char *filename = abspath("image.metadata.fits", DVO_MAX_PATH);
-      ImageMetadataSave (filename, image, Nimage);
-
-      REALLOCATE (targv, char *, targc + 2);
-      targv[targc+0] = strcreate ("-image-metadata");
-      targv[targc+1] = strcreate (filename);
-      targc += 2;
-    }
-
-    // call the remote client
-    int status = HostTableParallelOps (targc, targv, RESULT_FILE, TRUE, 0, VERBOSE);
-    if (vec) free (vec);
-    
-    // free up targv
-    for (i = 0; i < targc; i++) {
-      free (targv[i]);
-    }
-    free (targv);
-
-    return status;
-  }
 
   // get vectors corresponding to coordinates of interest
@@ -193,4 +121,77 @@
     remove_argument (1, &argc, argv);
   }
+
+  /* load regions which contain all supplied RA,DEC coordinates */
+  if ((skylist = SelectRegionsByCoordVectors (RAvec, DECvec)) == NULL) goto escape;
+
+  if (PARALLEL && !HOST_ID) {
+
+    // We need to copy the args to a temp array and modify them so that we send the
+    // correct set to the remote client.  The args list looks like this:
+    // if (!CoordsFile) : mmatch (RADIUS) field, ... [we removed RA & DEC above]
+    // if ( CoordsFile) : mmatch (RADIUS) field, ... [because we stripped off the -coords filename elements]
+
+    // allocate the temp array and copy all but (RA) (DEC)
+    int targc = 0;
+    char **targv = NULL;
+    ALLOCATE (targv, char *, argc + 2);
+    for (i = 0; i < argc; i++) {
+      targv[targc] = strcreate (argv[i]);
+      targc ++;
+    }
+
+    // if not specified, create the coords.fits input file
+    // NOTE: RAvec, DECvec were set above
+    if (!CoordsFile) {
+      ALLOCATE (vec, Vector *, 2);
+      vec[0] = RAvec;
+      vec[1] = DECvec;
+
+      // XXX this is now set for both cases...
+      CoordsFile = abspath("coords.fits", 1024);
+      int status = WriteVectorTableFITS (CoordsFile, "COORDS", vec, 2, FALSE, NULL);
+      if (!status) goto escape;
+    }
+
+    // add the coords file to the args list
+    targv[targc+0] = strcreate ("-coords");
+    targv[targc+1] = CoordsFile; // this gets freed with targv
+    targc += 2;
+    
+    // if needed, add the index vector to the args list
+    if (IDXvec) {
+      REALLOCATE (targv, char *, targc + 2);
+      targv[targc+0] = strcreate ("-index");
+      targv[targc+1] = strcreate (IDXvec[0].name);
+      targc += 2;
+    }      
+
+    if (loadImages) {
+      Image *image;
+      off_t Nimage;
+      if ((image = LoadImagesDVO (&Nimage)) == NULL) goto escape;
+
+      char *filename = abspath("image.metadata.fits", DVO_MAX_PATH);
+      ImageMetadataSave (filename, image, Nimage);
+
+      REALLOCATE (targv, char *, targc + 2);
+      targv[targc+0] = strcreate ("-image-metadata");
+      targv[targc+1] = strcreate (filename);
+      targc += 2;
+    }
+
+    // call the remote client
+    int status = HostTableParallelOps (skylist, targc, targv, RESULT_FILE, TRUE, 0, VERBOSE);
+    if (vec) free (vec);
+    
+    // free up targv
+    for (i = 0; i < targc; i++) {
+      free (targv[i]);
+    }
+    free (targv);
+
+    return status;
+  } // END of remote call section
+
   RADIUS = atof (argv[1]);
   remove_argument (1, &argc, argv);
@@ -209,6 +210,4 @@
   }
 
-  /* load regions which contain all supplied RA,DEC coordinates */
-  if ((skylist = SelectRegionsByCoordVectors (RAvec, DECvec)) == NULL) goto escape;
 
   /* create output storage vectors */
Index: trunk/Ohana/src/opihi/dvo/photometry.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/photometry.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/photometry.c	(revision 35416)
@@ -1127,5 +1127,5 @@
   double value;
   Image *image;
-  Coords *mosaic;
+  // Coords *mosaic;
 
   value = 0;
@@ -1193,8 +1193,9 @@
 # endif
       break;
+# if 0
     case MEAS_XMOSAIC: /* OK */
       ra  = average[0].R - measure[0].dR / 3600.0;
       dec = average[0].D - measure[0].dD / 3600.0;
-      mosaic = MatchMosaic (measure[0].t, measure[0].photcode);
+      mosaic = MatchMosaic (measure[0].t, measure[0].photcode); // XXX not used anymore
       if (mosaic == NULL) break;
       RD_to_XY (&x, &y, ra, dec, mosaic);
@@ -1204,9 +1205,10 @@
       ra  = average[0].R - measure[0].dR / 3600.0;
       dec = average[0].D - measure[0].dD / 3600.0;
-      mosaic = MatchMosaic (measure[0].t, measure[0].photcode);
+      mosaic = MatchMosaic (measure[0].t, measure[0].photcode); // XXX not used anymore
       if (mosaic == NULL) break;
       RD_to_XY (&x, &y, ra, dec, mosaic);
       value = y;
       break;
+# endif
   }
   return (value);
Index: trunk/Ohana/src/opihi/dvo/remote.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/remote.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/remote.c	(revision 35416)
@@ -61,6 +61,18 @@
   }
 
+  // load the list of hosts
+  SkyTable *sky = GetSkyTable();
+  if (!sky) {
+    gprint (GP_ERR, "failed to load sky table for database\n");
+    return FALSE;
+  }
+  SkyList *skylist = NULL;
+  ALLOCATE (skylist, SkyList, 1);
+  skylist[0].Nregions = sky[0].Nregions;
+  strcpy (skylist[0].hosts, sky[0].hosts);
+
   // strip of the 'remote' and send the remaining arguments to the remote machine
-  int status = HostTableParallelOps (argc - 1, &argv[1], NULL, ReadVectors, 0, VERBOSE);
+  int status = HostTableParallelOps (skylist, argc - 1, &argv[1], NULL, ReadVectors, 0, VERBOSE);
+  free (skylist);
   return status;
 }
Index: trunk/Ohana/src/opihi/dvo/skyregion.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/skyregion.c	(revision 35263)
+++ trunk/Ohana/src/opihi/dvo/skyregion.c	(revision 35416)
@@ -98,4 +98,5 @@
   new[0].Nregions = 0;
   new[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (new[0].hosts, sky[0].hosts);
 
   // output list
@@ -107,4 +108,5 @@
   list[0].Nregions = 0;
   list[0].ownElements = FALSE; // this list is only holding a view to the elements
+  strcpy (list[0].hosts, sky[0].hosts);
 
   for (i = 0; i < Npts; i++) {
Index: trunk/Ohana/src/opihi/include/dvoshell.h
===================================================================
--- trunk/Ohana/src/opihi/include/dvoshell.h	(revision 35263)
+++ trunk/Ohana/src/opihi/include/dvoshell.h	(revision 35416)
@@ -99,6 +99,6 @@
 dbValue      dbExtractImages        PROTO((Image *image, off_t Nimage, off_t N, dbField *field));
 
-int          HostTableLaunchJobs    PROTO((HostTable *table, char *basecmd, char *options, int VERBOSE));
-int          HostTableParallelOps   PROTO((int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE));
+int          HostTableLaunchJobs    PROTO((SkyList *sky, HostTable *table, char *basecmd, char *options, int VERBOSE));
+int          HostTableParallelOps   PROTO((SkyList *sky, int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE));
 int          HostTableReloadResults PROTO((char *uniquer, int VERBOSE));
 int          HostTableGetResults    PROTO((char *uniquer, int VERBOSE));
