Index: trunk/Ohana/Makefile.in
===================================================================
--- trunk/Ohana/Makefile.in	(revision 39693)
+++ trunk/Ohana/Makefile.in	(revision 39926)
@@ -138,6 +138,8 @@
 
 rebuild:
+	@date 
 	$(MAKE) clean
 	$(MAKE) install
+	@date 
 
 # standard rules: targets are foo, foo.clean, foo.install, foo.dist
Index: trunk/Ohana/src/addstar/Makefile
===================================================================
--- trunk/Ohana/src/addstar/Makefile	(revision 39693)
+++ trunk/Ohana/src/addstar/Makefile	(revision 39926)
@@ -25,4 +25,5 @@
 load2mass    : $(BIN)/load2mass.$(ARCH)
 loadgalphot  : $(BIN)/loadgalphot.$(ARCH)
+loadgaia     : $(BIN)/loadgaia.$(ARCH)
 loadstarpar  : $(BIN)/loadstarpar.$(ARCH)
 loadstarpar_client : $(BIN)/loadstarpar_client.$(ARCH)
@@ -42,5 +43,5 @@
 # programs in 'SERVER' use the client-server concept and are out of date
 
-INSTALL = addstar addstar_client sedstar loadgalphot loadstarpar loadstarpar_client setobjflags setobjflags_client loadICRF loadICRF_client skycells mkcmf dumpskycells findskycell load2mass loadwise loadtycho loadbsc loadsupercos 
+INSTALL = addstar addstar_client sedstar loadgalphot loadgaia loadstarpar loadstarpar_client setobjflags setobjflags_client loadICRF loadICRF_client skycells mkcmf dumpskycells findskycell load2mass loadwise loadtycho loadbsc loadsupercos 
 SERVER  = addstarc addstard addstart
 
@@ -267,8 +268,20 @@
 $(SRC)/psps_ids.$(ARCH).o
 
-# $(SRC)/SkyRegionUtils.$(ARCH).o 
-# $(SRC)/loadstarpar_io.$(ARCH).o 
-# $(SRC)/loadgalphot_remote_hosts.$(ARCH).o 
-# $(SRC)/loadgalphot_save_remote.$(ARCH).o 
+LOAD-GAIA = \
+$(SRC)/loadgaia.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/args_loadgaia.$(ARCH).o \
+$(SRC)/find_matches_gaia.$(ARCH).o \
+$(SRC)/loadgaia_catalog.$(ARCH).o \
+$(SRC)/loadgaia_make_subset.$(ARCH).o \
+$(SRC)/loadgaia_readstars.$(ARCH).o \
+$(SRC)/loadgaia_table.$(ARCH).o \
+$(SRC)/resort_catalog.$(ARCH).o \
+$(SRC)/build_links.$(ARCH).o \
+$(SRC)/strhash.$(ARCH).o \
+$(SRC)/sortIDs.$(ARCH).o \
+$(SRC)/psps_ids.$(ARCH).o
 
 LOAD-STARPAR = \
@@ -493,4 +506,5 @@
 $(LOAD-2MASS)  	       : $(INC)/addstar.h $(INC)/2mass.h
 $(LOAD-GALPHOT)	       : $(INC)/addstar.h $(INC)/loadgalphot.h
+$(LOAD-GAIA)	       : $(INC)/addstar.h $(INC)/gaia.h
 $(LOAD-STARPAR)	       : $(INC)/addstar.h $(INC)/loadstarpar.h
 $(LOAD-STARPAR-CLIENT) : $(INC)/addstar.h $(INC)/loadstarpar.h
@@ -514,4 +528,5 @@
 $(BIN)/loadbsc.$(ARCH)        : $(LOAD-BSC)
 $(BIN)/loadgalphot.$(ARCH)    : $(LOAD-GALPHOT)
+$(BIN)/loadgaia.$(ARCH)       : $(LOAD-GAIA)
 $(BIN)/loadstarpar.$(ARCH)    : $(LOAD-STARPAR)
 $(BIN)/loadstarpar_client.$(ARCH) : $(LOAD-STARPAR-CLIENT)
Index: trunk/Ohana/src/addstar/include/gaia.h
===================================================================
--- trunk/Ohana/src/addstar/include/gaia.h	(revision 39926)
+++ trunk/Ohana/src/addstar/include/gaia.h	(revision 39926)
@@ -0,0 +1,44 @@
+
+typedef struct {
+  double R, D;
+  Measure measure;
+  int flag; // in a subset?
+  int found; // assigned to an object?
+} Gaia_Stars;
+
+int   HOST_ID;
+char *HOSTDIR;
+char *CPT_FILE;
+char *INPUT;
+
+AddstarClientOptions args_loadgaia (int *argc, char **argv, AddstarClientOptions options);
+AddstarClientOptions args_loadgaia_client (int *argc, char **argv, AddstarClientOptions options);
+
+int loadgaia_table (int Nstart, int Nend, SkyList *skylistInput, HostTable *hosts, char **filename, AddstarClientOptions *options);
+
+Gaia_Stars *loadgaia_make_subset (Gaia_Stars *stars, int Nstars, int start, SkyRegion *region, int *nsubset);
+
+int loadgaia_save_remote (Gaia_Stars *stars, int Nstars, HostTable *hosts, SkyRegion *region, char *fullname, AddstarClientOptions *options);
+
+int save_remote_host (HostInfo *host);
+
+int init_remote_hosts (void);
+void free_remote_hosts (void);
+int find_empty_slot (void);
+int harvest_all (void);
+int harvest_host (void);
+
+int loadgaia_catalog (Gaia_Stars *stars, int Nstars, SkyRegion *region, char *filename, AddstarClientOptions *options);
+
+int galactic_to_celestial (double *R, double *D, double l, double b);
+
+int find_matches_gaia (SkyRegion *region, Gaia_Stars *stars, int Nstars, Catalog *catalog, AddstarClientOptions *options);
+
+int loadgaia_save_stars (char *filename, Gaia_Stars *stars, int Nstars);
+Gaia_Stars *loadgaia_load_stars (char *filename, int *nstars);
+
+Gaia_Stars *loadgaia_readstars (char *filename, Gaia_Stars *stars, int *nstars, AddstarClientOptions *options);
+
+int loadgaia_sortStars (Gaia_Stars *stars, int Nstars);
+
+int loadgaia_tmpdir (void);
Index: trunk/Ohana/src/addstar/src/args_loadgaia.c
===================================================================
--- trunk/Ohana/src/addstar/src/args_loadgaia.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/args_loadgaia.c	(revision 39926)
@@ -0,0 +1,144 @@
+# include "addstar.h"
+# include "gaia.h"
+
+static void help (void);
+
+AddstarClientOptions args_loadgaia (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);
+  }
+  /* override any header PHOTCODE values */
+  options.photcode = 0;
+  if ((N = get_argument (*argc, argv, "-p"))) {
+    remove_argument (N, argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if ((N = get_argument (*argc, argv, "-photcode"))) {
+    remove_argument (N, argc, argv);
+    options.photcode = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (!options.photcode) {
+    fprintf (stderr, "ERROR: please supply a photcode name with [-p name]\n");
+    exit (2);
+  }
+
+  /* provide a time for dataset */
+  options.timeref = 0; 
+  if ((N = get_argument (*argc, argv, "-time"))) {
+    time_t tmp;
+    remove_argument (N, argc, argv);
+    if (!ohana_str_to_time (argv[N], &tmp)) { 
+      fprintf (stderr, "syntax error in time\n");
+      exit (1);
+    }
+    options.timeref = tmp;
+    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 loadgaia */
+  // 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: loadgaia [options] (fitsfile) [..more files]\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE: loadgaia [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);
+}
Index: trunk/Ohana/src/addstar/src/find_matches_gaia.c
===================================================================
--- trunk/Ohana/src/addstar/src/find_matches_gaia.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/find_matches_gaia.c	(revision 39926)
@@ -0,0 +1,318 @@
+# include "addstar.h"
+# include "gaia.h"
+
+int find_matches_gaia (SkyRegion *region, Gaia_Stars *stars, int NstarsIn, Catalog *tgtcat, AddstarClientOptions *options) {
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+  int Nsec     = GetPhotcodeNsec (options->photcode);
+
+  /** allocate local arrays (stars) **/
+  ALLOCATE_PTR (X1, double, NstarsIn);
+  ALLOCATE_PTR (Y1, double, NstarsIn);
+  ALLOCATE_PTR (N1, off_t,  NstarsIn);
+
+  /** allocate local arrays (tgtcat) **/
+  off_t NAVE = tgtcat[0].Naverage;
+  off_t Nave = tgtcat[0].Naverage;
+  ALLOCATE_PTR (X2, double, NAVE);
+  ALLOCATE_PTR (Y2, double, NAVE);
+  ALLOCATE_PTR (N2, off_t,  NAVE);
+
+  /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
+
+  /* internal counters */
+  off_t Nmatch = 0;
+  off_t NMEAS = tgtcat[0].Nmeasure;
+  off_t Nmeas = tgtcat[0].Nmeasure;
+
+  off_t *next_meas = NULL;
+
+  // current max obj ID for this tgtcat
+  unsigned int objID = tgtcat[0].objID;
+  unsigned int catID = tgtcat[0].catID;
+
+  /* project onto rectilinear grid with 1 arcsec pixels. the choice of ARC projection has
+   * the advantage that every point in R,D has a mapping to a unique X,Y.  However, note
+   * that not all possible X,Y points map back to R,D and the local plate scale changes
+   * substantially far from the projection pole. We use the center of the region (tgtcat)
+   * for crval1,2.
+   */
+
+  Coords tcoords;
+  InitCoords (&tcoords, "DEC--ARC");
+  tcoords.crval1 = 0.5*(region[0].Rmin + region[0].Rmax);
+  if ((region[0].Dmax < 90) && (region[0].Dmin > -90)) {
+    tcoords.crval2 = 0.5*(region[0].Dmin + region[0].Dmax);
+  } else {
+    tcoords.crval2 = (region[0].Dmax >= 90) ? 90.0 : -90.0;
+  }
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+
+  /* build spatial index (RA sort) referencing input array sequence */
+  off_t Nstars = 0;
+  for (off_t i = 0; i < NstarsIn; i++) {
+    int status = RD_to_XY (&X1[Nstars], &Y1[Nstars], stars[i].R, stars[i].D, &tcoords);
+    if (!status) continue;
+    N1[Nstars] = i;
+    Nstars ++;
+  }
+  if (Nstars < 1) {
+    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", tgtcat[0].filename);
+    free (X1);
+    free (Y1);
+    free (N1);
+    free (X2);
+    free (Y2);
+    free (N2);
+    return 0;
+  }
+  if (Nstars > 1) sort_coords_index (X1, Y1, N1, Nstars);
+
+  /* build spatial index (RA sort) */
+  for (off_t i = 0; i < Nave; i++) {
+    RD_to_XY (&X2[i], &Y2[i], tgtcat[0].average[i].R, tgtcat[0].average[i].D, &tcoords);
+    N2[i] = i;
+  }
+  if (Nave > 1) sort_coords_index (X2, Y2, N2, Nave);
+
+  /* set up pointers for linked list of measure */
+  if (tgtcat[0].sorted && (tgtcat[0].Nmeasure == tgtcat[0].Nmeasure_disk)) {
+    // this version is only valid if we have done a full tgtcat load, and if the tgtcat
+    // is sorted while processed
+    next_meas = init_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
+  } else {
+    next_meas = build_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
+  }    
+
+  /* choose a radius for matches */
+  double RADIUS = (options->radius == 0) ? 2.0 : options->radius; /* provided by config */
+  double RADIUS2 = RADIUS*RADIUS;
+
+  /****************** find matched stars ********************/
+
+  for (off_t i = 0, j = 0; (i < Nstars) && (j < Nave); ) {
+    if (!finite(X1[i]) || !finite(Y1[i])) { 
+      i++; 
+      continue;
+    }
+    if (!finite(X2[j]) || !finite(Y2[j])) { 
+      j++; 
+      continue;
+    }
+    
+    /* negative dX: j is too large */
+    double dX = X1[i] - X2[j];
+    if (dX <= -1.02*RADIUS) {
+      i++;
+      continue;
+    }
+    /* positive dX, i is too large */
+    if (dX >= 1.02*RADIUS) {
+      j++;
+      continue;
+    }
+
+    // skip this star if already assigned to an object
+    if (stars[N1[i]].found) {
+        i++;
+        continue;
+    }
+
+    /* this block will match a given detection to the closest object within range of that detection.
+       XXX note that this matches ALL detections within range of the single object to that same object 
+       this is bad, but I cannot just go in linear order (ie, mark off each object as they are
+       used).  I should make a list of all Nobj * Ndet pairs in range and choose the matches
+       based on their separations.  UGH
+     */
+    
+    /* within match range; look for matches */
+    off_t Jmin = -1;
+    double Rmin = RADIUS2;
+    for (off_t J = j; (dX > -1.02*RADIUS) && (J < Nave); J++) {
+      /* find closest match for this detection */
+      dX = X1[i] - X2[J];
+      double dY = Y1[i] - Y2[J];
+      double dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+      if (dR < Rmin) {
+	Rmin = dR;
+	Jmin  = J;
+      }
+    }
+
+    /* no match, try next detection */ 
+    if (Jmin == -1) {
+      i++;
+      continue;
+    }
+
+    /*** a match is found, add to average, measure ***/
+    Nmatch ++;
+    off_t n = N2[Jmin];
+    off_t N = N1[i];
+
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS - 1) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next_meas, off_t, NMEAS);
+      REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
+    }
+
+    /** add measurement for this star **/
+
+    /* add to end of measurement list */
+    add_meas_link (&tgtcat[0].average[n], next_meas, Nmeas, NMEAS);
+
+    // set the new measurements
+    tgtcat[0].measure[Nmeas]          = stars[N].measure;
+
+    // measure now carries R,D (not dR,dD) 
+    tgtcat[0].measure[Nmeas].dbFlags  = 0;
+    tgtcat[0].measure[Nmeas].averef   = n;
+    tgtcat[0].measure[Nmeas].objID    = tgtcat[0].average[n].objID;
+    tgtcat[0].measure[Nmeas].catID    = tgtcat[0].catID;
+    
+    float dRoff = dvoOffsetR(&tgtcat[0].measure[Nmeas], &tgtcat[0].average[n]);
+
+    // rationalize dR
+    if (dRoff > +180.0*3600.0) {
+      // average on high end of boundary, move star up
+      tgtcat[0].measure[Nmeas].R += 360.0;
+      dRoff -= 360.0*3600.0;
+    }
+    if (dRoff < -180.0*3600.0) {
+      // average on low end of boundary, move star down
+      tgtcat[0].measure[Nmeas].R -= 360.0;
+      dRoff += 360.0*3600.0;
+    }
+    if (fabs(dRoff) > 10*RADIUS) {
+      // take declination into account and check again.
+      double cosD = cos(RAD_DEG*tgtcat[0].average[n].D);
+      if (fabs(dRoff*cosD) > 10*RADIUS) {
+	fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
+		 tgtcat[0].average[n].R, tgtcat[0].average[n].D, 
+		 stars[N].R, stars[N].D,
+		 X1[i], X2[Jmin], 
+		 Y1[i], Y2[Jmin]);
+	// XXX abort on this? -- this is a bad failure...
+      }
+    }
+
+    /* Nm is updated, but not written out in -update mode (for existing entries)
+       Nm is recalculated in build_meas_links if loaded table is not sorted */
+    tgtcat[0].average[n].Nmeasure ++;
+    Nmeas ++;
+
+    /* if we choose to flag close encounters, see find_matches.c */
+    /* if we choose to calculate RA,DEC averages, see update_coords.c */
+
+    stars[N].found = TRUE;
+    i++;
+  }
+
+  /*************** add unmatched stars *************************/
+
+  /** incorporate unmatched image stars, if this star is in field of this tgtcat **/
+  /* these new entries are all written out in UPDATE mode */ 
+  for (off_t i = 0; (i < Nstars) && !options->only_match; i++) {
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS - 1) {
+      NMEAS = Nmeas + 1000;
+      REALLOCATE (next_meas, off_t, NMEAS);
+      REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
+    }
+    if (Nave >= NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (tgtcat[0].average, Average, NAVE);
+      if (tgtcat[0].secfilt) {
+	// we only update the secfilt table if it has been allocated for output
+	REALLOCATE (tgtcat[0].secfilt, SecFilt, NAVE*tgtcat[0].Nsecfilt);
+      }
+    }
+
+    if (stars[i].found) continue;
+    if (!IN_REGION (stars[i].R, stars[i].D)) continue;
+
+    dvo_average_init (&tgtcat[0].average[Nave]);
+    tgtcat[0].average[Nave].R         	   = stars[i].R;
+    tgtcat[0].average[Nave].D         	   = stars[i].D;
+
+    tgtcat[0].average[Nave].Nmeasure  	   = 1;
+    tgtcat[0].average[Nave].measureOffset  = Nmeas;
+    tgtcat[0].average[Nave].objID     	   = objID;
+    tgtcat[0].average[Nave].catID     	   = catID;
+
+    if (PSPS_ID) {
+        tgtcat[0].average[Nave].extID = CreatePSPSObjectID(tgtcat[0].average[Nave].R, tgtcat[0].average[Nave].D);
+    }
+
+    objID ++;
+
+    // we only update the secfilt table if it has been allocated for output
+    for (int j = 0; tgtcat[0].secfilt && (j < Nsecfilt); j++) {
+      dvo_secfilt_init (&tgtcat[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
+    }
+
+    // supply the measurements from this detection
+    dvo_measure_init (&tgtcat[0].measure[Nmeas]);
+    tgtcat[0].measure[Nmeas] = stars[i].measure;
+
+    // the following measure elements cannot be set until here:
+    tgtcat[0].measure[Nmeas].dbFlags  = 0;
+    tgtcat[0].measure[Nmeas].averef   = Nave;
+    tgtcat[0].measure[Nmeas].objID    = tgtcat[0].average[Nave].objID;
+    tgtcat[0].measure[Nmeas].catID    = tgtcat[0].catID;
+
+    /* set the average magnitude if not already set and the photcode.equiv is not 0 */
+    /* in UPDATE mode, this value is not saved; use relphot to recalculate */
+    if (Nsec > -1) { 
+      tgtcat[0].secfilt[Nave*Nsecfilt+Nsec].M = PhotCat (&tgtcat[0].measure[Nmeas], MAG_CLASS_PSF);
+    }
+
+    Nmeas ++;
+
+    // update the next_meas pointer for this entry (last one for this star is -1)
+    next_meas[Nmeas-1] = -1;
+    stars[i].found = TRUE;
+    Nave ++;
+  }
+
+  REALLOCATE (tgtcat[0].average, Average, Nave);
+  REALLOCATE (tgtcat[0].measure, Measure, Nmeas);
+ 
+  if (options->nosort) {
+    tgtcat[0].sorted = FALSE;
+  } else {
+    tgtcat[0].sorted = TRUE;
+    tgtcat[0].measure = sort_measure (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas, next_meas);
+  }
+
+  /* check if the tgtcat has changed?  if no change, no need to write */
+  tgtcat[0].objID    = objID; // new max value, save on tgtcat close
+  tgtcat[0].Naverage = Nave;
+  tgtcat[0].Nmeasure = Nmeas;
+  tgtcat[0].Nsecfilt_mem = tgtcat[0].secfilt ? Nave*Nsecfilt : 0;
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas: "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT", ("OFF_T_FMT" matches)\n",  Nstars,  Nave,  Nmeas, Nmatch);
+
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (X2);
+  free (Y2);
+  free (N2);
+  free (next_meas);
+
+  return (Nmatch);
+}
+
+/* 
+   notes:
+   
+   for finding if a tgtcat star is in an image or an image star is in the tgtcat:
+   
+   tgtcats have boundaries defined by RA and DEC, but they may curve in projection
+   images have boundaries which are lines in pixels coords, but curve in RA and DEC
+   
+   tgtcat[0].found[Ncat] but stars[Nstar].found
+   
+*/
Index: trunk/Ohana/src/addstar/src/loadgaia.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgaia.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/loadgaia.c	(revision 39926)
@@ -0,0 +1,44 @@
+# include "addstar.h"
+# include "gaia.h"
+
+/* This is the DVO program to upload gaia detections from D. Finkbeiner into a DVO database.
+   It is modeled on the loadtycho program but the source files are FITS tables.
+
+   USAGE: loadgaia -D CATDIR (catdir) (gaiafile) [...more files]
+
+*/
+
+int main (int argc, char **argv) {
+
+  SkyTable *sky;
+  SkyList *skylist = NULL;
+  AddstarClientOptions options;
+
+  // need to construct these options with args_loadtycho...
+  SetSignals ();
+  options = ConfigInit (&argc, argv);
+  options = args_loadgaia (&argc, argv, options);
+
+  // load the full sky description table:
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  // generate the subset matching the user-selected region
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  int Nstart = 1;
+  int Nend = argc;
+  while (Nstart < Nend) {
+    Nstart = loadgaia_table (Nstart, Nend, skylist, NULL, argv, &options);
+  }
+
+  SkyTableFree (sky);
+  SkyListFree(skylist);
+  FreePhotcodeTable();
+  free (CATDIR);
+
+  ohana_memcheck (VERBOSE);
+  ohana_memdump (VERBOSE);
+  exit (0);
+}  
+
Index: trunk/Ohana/src/addstar/src/loadgaia_catalog.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgaia_catalog.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/loadgaia_catalog.c	(revision 39926)
@@ -0,0 +1,32 @@
+# include "addstar.h"
+# include "gaia.h"
+
+int loadgaia_catalog (Gaia_Stars *stars, int Nstars, SkyRegion *region, char *filename, AddstarClientOptions *options) {
+
+  Catalog catalog;
+
+  // now we have all of the loaded stars in this catalog
+  dvo_catalog_init (&catalog, TRUE);
+  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 = DVO_LOAD_AVERAGE | DVO_LOAD_SECFILT | DVO_LOAD_MEASURE;
+  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_gaia (region, stars, Nstars, &catalog, options);
+    
+  SetProtect (TRUE);
+  if (!dvo_catalog_save (&catalog, VERBOSE)) { fprintf (stderr, "ERROR: failed to save %s\n", catalog.filename); exit (1); }
+  if (!dvo_catalog_unlock (&catalog)) { fprintf (stderr, "ERROR: failed to unlock %s\n", catalog.filename); exit (1); }
+  SetProtect (FALSE);
+
+  dvo_catalog_free (&catalog);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/addstar/src/loadgaia_make_subset.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgaia_make_subset.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/loadgaia_make_subset.c	(revision 39926)
@@ -0,0 +1,44 @@
+# include "addstar.h"
+# include "gaia.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)
+
+Gaia_Stars *loadgaia_make_subset (Gaia_Stars *stars, int Nstars, int start, SkyRegion *region, int *nsubset) {
+
+  int i;
+
+  Gaia_Stars *subset = NULL;
+
+  // collect array of (Stars *) stars in a new output catalog
+  int Nsubset = 0;
+  int NSUBSET = 3000;
+  ALLOCATE (subset, Gaia_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, Gaia_Stars, NSUBSET, Nsubset, 10000);
+  }
+
+  *nsubset = Nsubset;
+  return subset;
+}
Index: trunk/Ohana/src/addstar/src/loadgaia_readstars.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgaia_readstars.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/loadgaia_readstars.c	(revision 39926)
@@ -0,0 +1,143 @@
+# include "addstar.h"
+# include "gaia.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");
+
+Gaia_Stars *loadgaia_readstars (char *filename, Gaia_Stars *stars, int *nstars, AddstarClientOptions *options) {
+
+  // read in the full FITS files
+  FILE *f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("can't read gaia 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 stars;
+  }
+  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 stars;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) {
+    fclose (f);
+    return stars;
+  }
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
+    fclose (f);
+    return stars;
+  }
+
+  char type[16];
+
+  GET_COLUMN (RA,      "RA",              	 double);
+  GET_COLUMN (DEC,     "DEC",             	 double);
+  GET_COLUMN (dRA,     "RA_ERROR",        	 float);
+  GET_COLUMN (dDEC,    "DEC_ERROR",       	 float);
+  GET_COLUMN (gMag,    "PHOT_G_MEAN_MAG", 	 float);
+  GET_COLUMN (dgFlux,  "PHOT_G_MEAN_FLUX_ERROR", float);
+  GET_COLUMN (Nobs,    "PHOT_G_N_OBS",           short);
+
+  int NstarsIn = Nrow;
+
+  // free the memory associated with the FITS files
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  fclose (f);
+
+  double Rmin = +360.0;
+  double Rmax = -360.0;
+  double Dmin = +360.0;
+  double Dmax = -360.0;
+
+  // start off where we finished on a previous read
+  int Nstars = *nstars;
+  int NSTARS = Nstars + 0.1*NstarsIn;
+
+  if (!stars) {
+    ALLOCATE (stars, Gaia_Stars, NSTARS);
+  } else {
+    REALLOCATE (stars, Gaia_Stars, NSTARS);
+  }
+
+  for (i = 0; i < NstarsIn; i++) {
+
+    Rmin = MIN (Rmin, RA[i]);
+    Rmax = MAX (Rmax, RA[i]);
+    Dmin = MIN (Dmin, DEC[i]);
+    Dmax = MAX (Dmax, DEC[i]);
+
+    float flux = pow(10.0, -0.4*(gMag[i] - 25.524770));
+
+    stars[Nstars].R = RA[i];
+    stars[Nstars].D = DEC[i];
+    stars[Nstars].flag  = FALSE;
+    stars[Nstars].found = FALSE;
+
+    dvo_measure_init (&stars[Nstars].measure);
+
+    stars[Nstars].measure.R = RA[i];
+    stars[Nstars].measure.D = DEC[i];
+    stars[Nstars].measure.dXccd = (int)(0x7fff*MAX(0.000,MIN(0.999, ((log10(dRA[i]) + 3.0)/6.0)))); 
+    stars[Nstars].measure.dYccd = (int)(0x7fff*MAX(0.000,MIN(0.999, ((log10(dDEC[i]) + 3.0)/6.0)))); 
+    // dXccd,dYccd range from 0 (10^-3) mas to 0x7fff (10^3 mas)
+    stars[Nstars].measure.M = gMag[i];
+    stars[Nstars].measure.dM = dgFlux[i] / flux;
+
+    stars[Nstars].measure.FluxPSF = flux;
+    stars[Nstars].measure.dFluxPSF = dgFlux[i];
+
+    stars[Nstars].measure.photcode = options->photcode;
+    stars[Nstars].measure.t = options->timeref;
+
+    Nstars ++;
+
+    CHECK_REALLOCATE (stars, Gaia_Stars, NSTARS, Nstars, 10000);
+  }
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  free (RA);
+  free (DEC);
+  free (dRA);
+  free (dDEC);
+  free (gMag);
+  free (dgFlux);
+  free (Nobs);
+
+  *nstars = Nstars;
+  return (stars);
+}
+
+int loadgaia_sortStars (Gaia_Stars *stars, int Nstars) {
+
+# define SWAPFUNC(A,B){ Gaia_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: trunk/Ohana/src/addstar/src/loadgaia_table.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgaia_table.c	(revision 39926)
+++ trunk/Ohana/src/addstar/src/loadgaia_table.c	(revision 39926)
@@ -0,0 +1,64 @@
+# include "addstar.h"
+# include "gaia.h"
+# define NSTARS_MAX 1000000
+
+int loadgaia_table (int Nstart, int Nend, SkyList *skylistInput, HostTable *hosts, char **filename, AddstarClientOptions *options) {
+  OHANA_UNUSED_PARAM(hosts);
+  
+  int i;
+
+  int Nstars = 0;
+  Gaia_Stars *stars = NULL;
+  for (i = Nstart; (Nstars < NSTARS_MAX) && (i < Nend); i++) {
+    // read the next file and append to the current set of stars
+    fprintf (stderr, "loading %s\n", filename[i]);
+    stars = loadgaia_readstars (filename[i], stars, &Nstars, options);
+  }
+  Nstart = i; // we pass back the entry for the next file to be read
+  if (!stars) return Nstart;
+
+  fprintf (stderr, "writing %d stars to dvo\n", Nstars);
+
+  // sort the stars by RA
+  loadgaia_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;
+    Gaia_Stars *subset = loadgaia_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
+    // NOTE: disable parallel mode for now: 
+    // loadgaia_save_remote (subset, Nsubset, hosts, region, skylist[0].filename[0], options);
+    loadgaia_catalog (subset, Nsubset, region, skylist[0].filename[0], options);
+    free (subset);
+    SkyListFree (skylist);
+  }
+
+  // wait for last remote clients to finish
+  // NOTE: disable parallel mode for now: 
+  // harvest_all ();
+
+  free (stars);
+  return Nstart;
+}
+
Index: trunk/Ohana/src/addstar/src/psps_ids.c
===================================================================
--- trunk/Ohana/src/addstar/src/psps_ids.c	(revision 39693)
+++ trunk/Ohana/src/addstar/src/psps_ids.c	(revision 39926)
@@ -42,5 +42,5 @@
 
     uint64_t part1, part2, part3;
-    part1 = (uint64_t)( izone  * 10000000000000LL) ; 
+    part1 = (uint64_t)( izone  * 10000000000000LL) ; // 10,000,000,000,000
     part2 = ((uint64_t)(ra * 1000000.)) * 10000 ; // 0 - 360*1e6 = 3.6e8 (< 29 bits)
     part3 = (int) (zresid * 10000.0) ; // 0 - 10000 (1 bit == 30/10000 arcsec) (< 14 bits)
@@ -48,2 +48,4 @@
     return part1 + part2 + part3;
 }
+
+// 10 000 000 000 000
Index: trunk/Ohana/src/delstar/include/delstar.h
===================================================================
--- trunk/Ohana/src/delstar/include/delstar.h	(revision 39693)
+++ trunk/Ohana/src/delstar/include/delstar.h	(revision 39926)
@@ -95,4 +95,5 @@
 int   SAVE_DELETES;
 int   SKIP_IMAGES;
+char *BACKUP_EXTNAME;
 
 time_t    START;
@@ -111,4 +112,9 @@
 
 // for DELETE_MEASURES_BY_MATCH, these are the ranges to delete:
+int DELETE_MIN_DET_ID;
+int DELETE_MAX_DET_ID;
+int DELETE_MIN_CAT_ID;
+int DELETE_MAX_CAT_ID;
+
 int DELETE_MIN_IMAGE_ID;
 int DELETE_MAX_IMAGE_ID;
@@ -118,5 +124,4 @@
 int DELETE_MIN_TIME;
 int DELETE_MAX_TIME;
-
 
 /*** delstar prototypes ***/
Index: trunk/Ohana/src/delstar/src/args.c
===================================================================
--- trunk/Ohana/src/delstar/src/args.c	(revision 39693)
+++ trunk/Ohana/src/delstar/src/args.c	(revision 39926)
@@ -202,4 +202,8 @@
   }
 
+  DELETE_MIN_DET_ID = 0;
+  DELETE_MAX_DET_ID = 0;
+  DELETE_MIN_CAT_ID = 0;
+  DELETE_MAX_CAT_ID = 0;
   DELETE_MIN_IMAGE_ID = 0;
   DELETE_MAX_IMAGE_ID = 0;
@@ -209,4 +213,8 @@
   DELETE_MAX_TIME = 0;
 
+  if ((N = get_argument (argc, argv, "-delete-min-detID")))  { remove_argument (N, &argc, argv); DELETE_MIN_DET_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-max-detID")))  { remove_argument (N, &argc, argv); DELETE_MAX_DET_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-min-catID")))  { remove_argument (N, &argc, argv); DELETE_MIN_CAT_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-max-catID")))  { remove_argument (N, &argc, argv); DELETE_MAX_CAT_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
   if ((N = get_argument (argc, argv, "-delete-min-imageID")))  { remove_argument (N, &argc, argv); DELETE_MIN_IMAGE_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
   if ((N = get_argument (argc, argv, "-delete-max-imageID")))  { remove_argument (N, &argc, argv); DELETE_MAX_IMAGE_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
@@ -221,4 +229,13 @@
     remove_argument (N, &argc, argv);
   }
+
+  BACKUP_EXTNAME = NULL;
+  if ((N = get_argument (argc, argv, "-backup-extname"))) {
+    remove_argument (N, &argc, argv);
+    BACKUP_EXTNAME = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!BACKUP_EXTNAME) BACKUP_EXTNAME = strcreate (".bck");
+
   SAVE_DELETES = FALSE;
   if ((N = get_argument (argc, argv, "-save-deletes"))) {
@@ -471,4 +488,5 @@
     remove_argument (N, &argc, argv);
   }
+
   if ((N = get_argument (argc, argv, "-delete-measures-by-match"))) {
     if (MODE != MODE_NONE) usage();
@@ -477,4 +495,9 @@
     SKIP_IMAGES = TRUE; // we do not need to load the images for -dup-measures
   }
+
+  DELETE_MIN_DET_ID = 0;
+  DELETE_MAX_DET_ID = 0;
+  DELETE_MIN_CAT_ID = 0;
+  DELETE_MAX_CAT_ID = 0;
   DELETE_MIN_IMAGE_ID = 0;
   DELETE_MAX_IMAGE_ID = 0;
@@ -484,4 +507,8 @@
   DELETE_MAX_TIME = 0;
 
+  if ((N = get_argument (argc, argv, "-delete-min-detID")))  { remove_argument (N, &argc, argv); DELETE_MIN_DET_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-max-detID")))  { remove_argument (N, &argc, argv); DELETE_MAX_DET_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-min-catID")))  { remove_argument (N, &argc, argv); DELETE_MIN_CAT_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
+  if ((N = get_argument (argc, argv, "-delete-max-catID")))  { remove_argument (N, &argc, argv); DELETE_MAX_CAT_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
   if ((N = get_argument (argc, argv, "-delete-min-imageID")))  { remove_argument (N, &argc, argv); DELETE_MIN_IMAGE_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
   if ((N = get_argument (argc, argv, "-delete-max-imageID")))  { remove_argument (N, &argc, argv); DELETE_MAX_IMAGE_ID = atoi(argv[N]); remove_argument (N, &argc, argv); }
@@ -496,4 +523,11 @@
     remove_argument (N, &argc, argv);
   }
+  BACKUP_EXTNAME = NULL;
+  if ((N = get_argument (argc, argv, "-backup-extname"))) {
+    remove_argument (N, &argc, argv);
+    BACKUP_EXTNAME = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!BACKUP_EXTNAME) BACKUP_EXTNAME = strcreate (".bck");
 
   if ((N = get_argument (argc, argv, "-fix-LAP"))) {
Index: trunk/Ohana/src/delstar/src/delete_duplicate_measures.c
===================================================================
--- trunk/Ohana/src/delstar/src/delete_duplicate_measures.c	(revision 39693)
+++ trunk/Ohana/src/delstar/src/delete_duplicate_measures.c	(revision 39926)
@@ -111,13 +111,13 @@
 
     // save backup of original cpm file
-    if (!dvo_catalog_subset_backup (&catalog, ".dlx")) {
+    if (!dvo_catalog_subset_backup (&catalog, ".dlz")) {
       fprintf (stderr, "ERROR: failed to make backup cpt table for catalog %s\n", catalog.filename);
       exit (1);
     }
-    if (!dvo_catalog_subset_backup (catalog.measure_catalog, ".d1x")) {
+    if (!dvo_catalog_subset_backup (catalog.measure_catalog, ".d1z")) {
       fprintf (stderr, "ERROR: failed to make backup cpm table for catalog %s\n", catalog.filename);
       exit (1);
     }
-    if (!dvo_catalog_subset_backup (catalog.secfilt_catalog, ".dlx")) {
+    if (!dvo_catalog_subset_backup (catalog.secfilt_catalog, ".dlz")) {
       fprintf (stderr, "ERROR: failed to make backup cps table for catalog %s\n", catalog.filename);
       exit (1);
@@ -377,5 +377,5 @@
   if (SAVE_DUPLICATES) {
     char savename[DVO_MAX_PATH];
-    snprintf (savename, DVO_MAX_PATH, "%s.save.0912", catalog->filename);
+    snprintf (savename, DVO_MAX_PATH, "%s.save.0914", catalog->filename);
     struct stat filestat;
     int myStatus = stat (savename, &filestat);
Index: trunk/Ohana/src/delstar/src/delete_measures_by_match.c
===================================================================
--- trunk/Ohana/src/delstar/src/delete_measures_by_match.c	(revision 39693)
+++ trunk/Ohana/src/delstar/src/delete_measures_by_match.c	(revision 39926)
@@ -13,4 +13,8 @@
 
   int validOptions = FALSE;
+  validOptions |= DELETE_MAX_CAT_ID;
+  validOptions |= DELETE_MIN_CAT_ID;
+  validOptions |= DELETE_MAX_DET_ID;
+  validOptions |= DELETE_MIN_DET_ID;
   validOptions |= DELETE_MAX_IMAGE_ID;
   validOptions |= DELETE_MIN_IMAGE_ID;
@@ -26,4 +30,6 @@
   fprintf (stderr, "deleting measurements matching the following\n");
   fprintf (stderr, "image ID range : %d to %d\n", DELETE_MIN_IMAGE_ID, DELETE_MAX_IMAGE_ID);
+  fprintf (stderr, "det ID range : %d to %d\n", DELETE_MIN_DET_ID, DELETE_MAX_DET_ID);
+  fprintf (stderr, "cat ID range : %d to %d\n", DELETE_MIN_CAT_ID, DELETE_MAX_CAT_ID);
   fprintf (stderr, "photcode range : %d to %d\n", DELETE_MIN_PHOTCODE, DELETE_MAX_PHOTCODE);
   fprintf (stderr, "time range (UNIX) : %d to %d\n", DELETE_MIN_TIME, DELETE_MAX_TIME);
@@ -133,13 +139,13 @@
 
     // save backup of original cpm file
-    if (!dvo_catalog_subset_backup (&catalog, ".dlz")) {
+    if (!dvo_catalog_subset_backup (&catalog, BACKUP_EXTNAME)) {
       fprintf (stderr, "ERROR: failed to make backup cpt table for catalog %s\n", catalog.filename);
       exit (1);
     }
-    if (!dvo_catalog_subset_backup (catalog.measure_catalog, ".d1z")) {
+    if (!dvo_catalog_subset_backup (catalog.measure_catalog, BACKUP_EXTNAME)) {
       fprintf (stderr, "ERROR: failed to make backup cpm table for catalog %s\n", catalog.filename);
       exit (1);
     }
-    if (!dvo_catalog_subset_backup (catalog.secfilt_catalog, ".dlz")) {
+    if (!dvo_catalog_subset_backup (catalog.secfilt_catalog, BACKUP_EXTNAME)) {
       fprintf (stderr, "ERROR: failed to make backup cps table for catalog %s\n", catalog.filename);
       exit (1);
@@ -214,4 +220,9 @@
 	      UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax);
 
+    if (DELETE_MIN_DET_ID) strextend (&command, "-delete-min-detID %d", DELETE_MIN_DET_ID);
+    if (DELETE_MAX_DET_ID) strextend (&command, "-delete-max-detID %d", DELETE_MAX_DET_ID);
+    if (DELETE_MIN_CAT_ID) strextend (&command, "-delete-min-catID %d", DELETE_MIN_CAT_ID);
+    if (DELETE_MAX_CAT_ID) strextend (&command, "-delete-max-catID %d", DELETE_MAX_CAT_ID);
+
     if (DELETE_MIN_IMAGE_ID) strextend (&command, "-delete-min-imageID %d", DELETE_MIN_IMAGE_ID);
     if (DELETE_MAX_IMAGE_ID) strextend (&command, "-delete-max-imageID %d", DELETE_MAX_IMAGE_ID);
@@ -234,4 +245,6 @@
     if (UPDATE)     	 { strextend (&command, "-update");             }
     if (SAVE_DELETES)    { strextend (&command, "-save-deletes");    }
+
+    if (BACKUP_EXTNAME)  { strextend (&command, "-backup-extname %s", BACKUP_EXTNAME);    }
 
     fprintf (stderr, "command: %s\n", command);
@@ -356,4 +369,10 @@
 
     // does this measure match our selection criteria?
+    if (measure[i].detID > DELETE_MAX_DET_ID) continue;
+    if (measure[i].detID < DELETE_MIN_DET_ID) continue;
+
+    if (measure[i].catID > DELETE_MAX_CAT_ID) continue;
+    if (measure[i].catID < DELETE_MIN_CAT_ID) continue;
+
     if (measure[i].imageID > DELETE_MAX_IMAGE_ID) continue;
     if (measure[i].imageID < DELETE_MIN_IMAGE_ID) continue;
@@ -367,7 +386,7 @@
     measureDrop[i] = TRUE;
     off_t N = measure[i].averef;
-    if (VERBOSE) fprintf (stderr, "0x%08x 0x%08x %8.4f %8.4f %5d\n", measure[i].imageID, measure[i].detID, average[N].R, average[N].D, measure[i].photcode);
+    if (VERBOSE) fprintf (stderr, "0x%08x 0x%08x 0x%08x %8.4f %8.4f %5d\n", measure[i].imageID, measure[i].detID, measure[i].catID, average[N].R, average[N].D, measure[i].photcode);
     if (fsave) {
-      fprintf (fsave, "0x%08x 0x%08x %8.4f %8.4f %5d\n", measure[i].imageID, measure[i].detID, average[N].R, average[N].D, measure[i].photcode);
+      fprintf (fsave, "0x%08x 0x%08x 0x%08x %8.4f %8.4f %5d\n", measure[i].imageID, measure[i].detID, measure[i].catID, average[N].R, average[N].D, measure[i].photcode);
     }
     if (isGPC1chip(measure[i].photcode)) {
Index: trunk/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 39693)
+++ trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 39926)
@@ -61,4 +61,5 @@
 int    SKIP_MEASURE;
 int    SKIP_LENSING;
+int    SKIP_LENSOBJ;
 int    SKIP_STARPAR;
 int    SKIP_GALPHOT;
@@ -171,24 +172,29 @@
 off_t 	  *build_measure_links    PROTO((Average *average, off_t Naverage, Measure *measure, off_t Nmeasure));
 off_t 	  *init_measure_links     PROTO((Average *average, off_t Naverage, Measure *measure, off_t Nmeasure));
-int   	   add_meas_link     	  PROTO((Average *average, off_t *next, off_t Nmeasure, off_t NMEASURE));
+int   	   add_measure_link    	  PROTO((Average *average, off_t *next, off_t Nmeasure, off_t NMEASURE));
 Measure   *sort_measure     	  PROTO((Average *average, off_t Naverage, Measure *measure, off_t Nmeasure, off_t *next));
 
 off_t 	  *build_lensing_links    PROTO((Average *average, off_t Naverage, Lensing *lensing, off_t Nlensing));
 off_t 	  *init_lensing_links     PROTO((Average *average, off_t Naverage, Lensing *lensing, off_t Nlensing));
-int   	   add_lens_link     	  PROTO((Average *average, off_t *next, off_t Nlensing, off_t NLENSING));
+int   	   add_lensing_link    	  PROTO((Average *average, off_t *next, off_t Nlensing, off_t NLENSING));
 Lensing   *sort_lensing     	  PROTO((Average *average, off_t Naverage, Lensing *lensing, off_t Nlensing, off_t *next));
+
+off_t 	  *build_lensobj_links    PROTO((Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj));
+off_t 	  *init_lensobj_links     PROTO((Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj));
+int   	   add_lensobj_link    	  PROTO((Average *average, off_t *next, off_t Nlensobj, off_t NLENSOBJ));
+Lensobj   *sort_lensobj     	  PROTO((Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj, off_t *next));
 
 off_t 	  *build_starpar_links    PROTO((Average *average, off_t Naverage, StarPar *starpar, off_t Nstarpar));
 off_t 	  *init_starpar_links     PROTO((Average *average, off_t Naverage, StarPar *starpar, off_t Nstarpar));
-int   	   add_star_link     	  PROTO((Average *average, off_t *next, off_t Nstarpar, off_t NSTARPAR));
+int   	   add_starpar_link     	  PROTO((Average *average, off_t *next, off_t Nstarpar, off_t NSTARPAR));
 StarPar   *sort_starpar     	  PROTO((Average *average, off_t Naverage, StarPar *starpar, off_t Nstarpar, off_t *next));
 
 off_t 	  *build_galphot_links    PROTO((Average *average, off_t Naverage, GalPhot *galphot, off_t Ngalphot));
 off_t 	  *init_galphot_links     PROTO((Average *average, off_t Naverage, GalPhot *galphot, off_t Ngalphot));
-int   	   add_galp_link     	  PROTO((Average *average, off_t *next, off_t Ngalphot, off_t NGALPHOT));
+int   	   add_galphot_link     	  PROTO((Average *average, off_t *next, off_t Ngalphot, off_t NGALPHOT));
 GalPhot   *sort_galphot     	  PROTO((Average *average, off_t Naverage, GalPhot *galphot, off_t Ngalphot, off_t *next));
 
 off_t 	  *init_missing_links     PROTO((Average *average, off_t Naverage, Missing *missing, off_t Nmissing));
-int   	   add_miss_link     	  PROTO((Average *average, off_t *next, off_t Nmissing));
+int   	   add_missing_link     	  PROTO((Average *average, off_t *next, off_t Nmissing));
 Missing   *sort_missing     	  PROTO((Average *average, off_t Naverage, Missing *missing, off_t Nmissing, off_t *next_miss));
 
Index: trunk/Ohana/src/dvomerge/src/LoadCatalog.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/LoadCatalog.c	(revision 39693)
+++ trunk/Ohana/src/dvomerge/src/LoadCatalog.c	(revision 39926)
@@ -9,7 +9,6 @@
 
   // always load all of the data (if any exists)
-  // XXXX TEMP HACK : skip GALPHOT
 
-  catalog[0].catflags = DVO_LOAD_AVERAGE | DVO_LOAD_MISSING | DVO_LOAD_SECFILT | DVO_LOAD_LENSOBJ;
+  catalog[0].catflags = DVO_LOAD_AVERAGE | DVO_LOAD_MISSING | DVO_LOAD_SECFILT;
 
   if (SKIP_MEASURE) {
@@ -23,4 +22,10 @@
   } else {
     catalog[0].catflags = catalog[0].catflags | DVO_LOAD_LENSING;
+  }
+
+  if (SKIP_LENSOBJ)  {
+    catalog[0].catflags = catalog[0].catflags | DVO_SKIP_LENSOBJ;
+  } else {
+    catalog[0].catflags = catalog[0].catflags | DVO_LOAD_LENSOBJ;
   }
 
Index: trunk/Ohana/src/dvomerge/src/args.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/args.c	(revision 39693)
+++ trunk/Ohana/src/dvomerge/src/args.c	(revision 39926)
@@ -56,4 +56,9 @@
   if ((N = get_argument (*argc, argv, "-skip-lensing"))) {
     SKIP_LENSING = TRUE;
+    remove_argument (N, argc, argv);
+  }
+  SKIP_LENSOBJ = FALSE;
+  if ((N = get_argument (*argc, argv, "-skip-lensobj"))) {
+    SKIP_LENSOBJ = TRUE;
     remove_argument (N, argc, argv);
   }
@@ -340,4 +345,9 @@
     remove_argument (N, argc, argv);
   }
+  SKIP_LENSOBJ = FALSE;
+  if ((N = get_argument (*argc, argv, "-skip-lensobj"))) {
+    SKIP_LENSOBJ = TRUE;
+    remove_argument (N, argc, argv);
+  }
   SKIP_STARPAR = FALSE;
   if ((N = get_argument (*argc, argv, "-skip-starpar"))) {
Index: trunk/Ohana/src/dvomerge/src/build_links.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/build_links.c	(revision 39693)
+++ trunk/Ohana/src/dvomerge/src/build_links.c	(revision 39926)
@@ -15,10 +15,10 @@
 data: they refer to the sequence number in the data blocks.
 
-next_meas is a list of the equivalent sequence of the measure block as if it were sorted.
+next_measure is a list of the equivalent sequence of the measure block as if it were sorted.
 
 to find the sequence of measurements for a given average:
 n_0 = average->measureOffset
-n_1 = next_meas[n_0]
-n_i = next_meas[n_i-1]
+n_1 = next_measure[n_0]
+n_i = next_measure[n_i-1]
 
 */
@@ -31,5 +31,5 @@
 
   off_t i, j, N;
-  off_t *next_meas;
+  off_t *next_measure;
 
   if (!measure) return NULL;
@@ -38,5 +38,5 @@
   N = 0;
 
-  ALLOCATE (next_meas, off_t, Nmeasure);
+  ALLOCATE (next_measure, off_t, Nmeasure);
   for (i = 0; i < Naverage; i++) {
     if (!average[i].Nmeasure) continue;
@@ -45,10 +45,10 @@
     for (j = 0; j < average[i].Nmeasure - 1; j++, N++) {
       myAssert (measure[m+j+1].averef == i, "not sorted");
-      next_meas[N] = N + 1;
+      next_measure[N] = N + 1;
       if (N >= Nmeasure) {
 	fprintf (stderr, "WARNING: N out of bounds (1)\n");
       }
     }
-    next_meas[N] = -1;
+    next_measure[N] = -1;
     if (N >= Nmeasure) {
       fprintf (stderr, "WARNING: N out of bounds (2)\n");
@@ -61,5 +61,5 @@
     N++;
   }
-  return (next_meas);
+  return (next_measure);
 }
 
@@ -74,7 +74,7 @@
 
   off_t i, m, k, Nm, averef;
-  off_t *next_meas;
-
-  ALLOCATE (next_meas, off_t, Nmeasure);
+  off_t *next_measure;
+
+  ALLOCATE (next_measure, off_t, Nmeasure);
 
   /* reset the Nm, offset values for average */
@@ -87,5 +87,5 @@
     averef = measure[Nm].averef;
     m = average[averef].measureOffset;  
-    next_meas[Nm] = -1;
+    next_measure[Nm] = -1;
 
     if (m == -1) { /* no links yet for source */
@@ -95,6 +95,6 @@
     }
 
-    for (k = 0; next_meas[m] != -1; k++) {
-      m = next_meas[m];
+    for (k = 0; next_measure[m] != -1; k++) {
+      m = next_measure[m];
       if (m >= Nmeasure) {
 	fprintf (stderr, "WARNING: m out of bounds (1)\n");
@@ -103,22 +103,22 @@
 
     average[averef].Nmeasure = k + 2;
-    next_meas[m] = Nm;
+    next_measure[m] = Nm;
     if (m >= Nmeasure) {
       fprintf (stderr, "WARNING: m out of bounds (2)\n");
     }
   }
-  return (next_meas);
+  return (next_measure);
 }
 
 /* average[].measureOffset, average[].Nmeasure are valid within an addstar run */
-int add_meas_link (Average *average, off_t *next_meas, off_t Nmeasure, off_t NMEASURE) {
+int add_measure_link (Average *average, off_t *next_measure, off_t Nmeasure, off_t NMEASURE) {
 
   off_t k, m;
 
-  /* if we have trouble, check validity of next_meas[m] : m < Nmeasure */
+  /* if we have trouble, check validity of next_measure[m] : m < Nmeasure */
   m = average[0].measureOffset;  
 
   for (k = 0; k < average[0].Nmeasure - 1; k++)  {
-    m = next_meas[m];
+    m = next_measure[m];
     if (m >= NMEASURE) {
       fprintf (stderr, "WARNING: m out of bounds (3)\n");
@@ -127,5 +127,5 @@
 
   /* set up references */
-  next_meas[Nmeasure] = -1;
+  next_measure[Nmeasure] = -1;
   if (Nmeasure >= NMEASURE) {
     fprintf (stderr, "WARNING: Nmeasure out of bounds (1)\n");
@@ -136,5 +136,5 @@
     average[0].measureOffset = Nmeasure;
   } else {
-    next_meas[m] = Nmeasure;
+    next_measure[m] = Nmeasure;
     if (m >= NMEASURE) {
       fprintf (stderr, "WARNING: m out of bounds (4)\n");
@@ -145,5 +145,5 @@
 }
 
-Measure *sort_measure (Average *average, off_t Naverage, Measure *measure, off_t Nmeasure, off_t *next_meas) {
+Measure *sort_measure (Average *average, off_t Naverage, Measure *measure, off_t Nmeasure, off_t *next_measure) {
 
   off_t i, k, n, np, N;
@@ -169,5 +169,5 @@
       tmpmeasure[N].averef = i;
       np = n;
-      n = next_meas[n];
+      n = next_measure[n];
     }
   }
@@ -183,15 +183,15 @@
 
   off_t i, j, N;
-  off_t *next_miss;
+  off_t *next_missing;
 
   N = 0;
 
-  ALLOCATE (next_miss, off_t, Nmissing);
+  ALLOCATE (next_missing, off_t, Nmissing);
   for (i = 0; i < Naverage; i++) {
     for (j = 0; j < average[i].Nmissing - 1; j++, N++) {
-      next_miss[N] = N + 1;
+      next_missing[N] = N + 1;
     }
     if (average[i].Nmissing > 0) {
-      next_miss[N] = -1;
+      next_missing[N] = -1;
       if (N >= Nmissing) {
 	fprintf (stderr, "overflow in init_missing_links");
@@ -202,8 +202,8 @@
 
   }
-  return (next_miss);
-}
-
-int add_miss_link (Average *average, off_t *next_miss, off_t Nmissing) {
+  return (next_missing);
+}
+
+int add_missing_link (Average *average, off_t *next_missing, off_t Nmissing) {
 
   off_t k, m;
@@ -212,13 +212,13 @@
   if (average[0].Nmissing < 1) {
     average[0].missingOffset = Nmissing;
-    next_miss[Nmissing] = -1;
+    next_missing[Nmissing] = -1;
     return (TRUE);
   }
 
   m = average[0].missingOffset;  
-  for (k = 0; k < average[0].Nmissing - 1; k++) m = next_miss[m];
+  for (k = 0; k < average[0].Nmissing - 1; k++) m = next_missing[m];
   /* set up references */
-  next_miss[Nmissing] = -1;
-  next_miss[m] = Nmissing;
+  next_missing[Nmissing] = -1;
+  next_missing[m] = Nmissing;
   return (TRUE);
 }
@@ -227,5 +227,5 @@
    we must always save the missing table, if it exists */
 
-Missing *sort_missing (Average *average, off_t Naverage, Missing *missing, off_t Nmissing, off_t *next_miss) {
+Missing *sort_missing (Average *average, off_t Naverage, Missing *missing, off_t Nmissing, off_t *next_missing) {
 
   off_t i, k, n, N;
@@ -240,5 +240,5 @@
     for (k = 0; k < average[i].Nmissing; k++, N++) {
       tmpmissing[N] = missing[n]; 
-      n = next_miss[n];
+      n = next_missing[n];
     }
   }
@@ -254,5 +254,5 @@
 
   off_t i, j, N;
-  off_t *next_lens;
+  off_t *next_lensing;
 
   if (!lensing) return NULL;
@@ -261,5 +261,5 @@
   N = 0;
 
-  ALLOCATE (next_lens, off_t, Nlensing);
+  ALLOCATE (next_lensing, off_t, Nlensing);
   for (i = 0; i < Naverage; i++) {
     if (!average[i].Nlensing) continue;
@@ -268,10 +268,10 @@
     for (j = 0; j < average[i].Nlensing - 1; j++, N++) {
       myAssert (lensing[m+j+1].averef == i, "not sorted");
-      next_lens[N] = N + 1;
+      next_lensing[N] = N + 1;
       if (N >= Nlensing) {
 	fprintf (stderr, "WARNING: N out of bounds (1)\n");
       }
     }
-    next_lens[N] = -1;
+    next_lensing[N] = -1;
     if (N >= Nlensing) {
       fprintf (stderr, "WARNING: N out of bounds (2)\n");
@@ -284,5 +284,5 @@
     N++;
   }
-  return (next_lens);
+  return (next_lensing);
 }
 
@@ -297,7 +297,7 @@
 
   off_t i, m, k, Nm, averef;
-  off_t *next_lens;
-
-  ALLOCATE (next_lens, off_t, Nlensing);
+  off_t *next_lensing;
+
+  ALLOCATE (next_lensing, off_t, Nlensing);
 
   /* reset the Nm, offset values for average */
@@ -310,5 +310,5 @@
     averef = lensing[Nm].averef;
     m = average[averef].lensingOffset;  
-    next_lens[Nm] = -1;
+    next_lensing[Nm] = -1;
 
     if (m == -1) { /* no links yet for source */
@@ -318,6 +318,6 @@
     }
 
-    for (k = 0; next_lens[m] != -1; k++) {
-      m = next_lens[m];
+    for (k = 0; next_lensing[m] != -1; k++) {
+      m = next_lensing[m];
       if (m >= Nlensing) {
 	fprintf (stderr, "WARNING: m out of bounds (1)\n");
@@ -326,22 +326,22 @@
 
     average[averef].Nlensing = k + 2;
-    next_lens[m] = Nm;
+    next_lensing[m] = Nm;
     if (m >= Nlensing) {
       fprintf (stderr, "WARNING: m out of bounds (2)\n");
     }
   }
-  return (next_lens);
+  return (next_lensing);
 }
 
 /* average[].lensingOffset, average[].Nlensing are valid within an addstar run */
-int add_lens_link (Average *average, off_t *next_lens, off_t Nlensing, off_t NLENSING) {
+int add_lensing_link (Average *average, off_t *next_lensing, off_t Nlensing, off_t NLENSING) {
 
   off_t k, m;
 
-  /* if we have trouble, check validity of next_lens[m] : m < Nlensing */
+  /* if we have trouble, check validity of next_lensing[m] : m < Nlensing */
   m = average[0].lensingOffset;  
 
   for (k = 0; k < average[0].Nlensing - 1; k++)  {
-    m = next_lens[m];
+    m = next_lensing[m];
     if (m >= NLENSING) {
       fprintf (stderr, "WARNING: m out of bounds (3)\n");
@@ -350,5 +350,5 @@
 
   /* set up references */
-  next_lens[Nlensing] = -1;
+  next_lensing[Nlensing] = -1;
   if (Nlensing >= NLENSING) {
     fprintf (stderr, "WARNING: Nlensing out of bounds (1)\n");
@@ -359,5 +359,5 @@
     average[0].lensingOffset = Nlensing;
   } else {
-    next_lens[m] = Nlensing;
+    next_lensing[m] = Nlensing;
     if (m >= NLENSING) {
       fprintf (stderr, "WARNING: m out of bounds (4)\n");
@@ -368,5 +368,5 @@
 }
 
-Lensing *sort_lensing (Average *average, off_t Naverage, Lensing *lensing, off_t Nlensing, off_t *next_lens) {
+Lensing *sort_lensing (Average *average, off_t Naverage, Lensing *lensing, off_t Nlensing, off_t *next_lensing) {
 
   off_t i, k, n, np, N;
@@ -392,9 +392,167 @@
       tmplensing[N].averef = i;
       np = n;
-      n = next_lens[n];
+      n = next_lensing[n];
     }
   }
   free (lensing);
   return (tmplensing);
+}
+
+/*** Lensobj ****************************************************************************************/
+
+/* build the initial links assuming the table is sorted, 
+   not partial, and has a correct set of average[].lensobjOffset,Nlensobj values */
+off_t *init_lensobj_links (Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj) {
+
+  off_t i, j, N;
+  off_t *next_lensobj;
+
+  if (!lensobj) return NULL;
+  if (SKIP_LENSOBJ) return NULL;
+
+  N = 0;
+
+  ALLOCATE (next_lensobj, off_t, Nlensobj);
+  for (i = 0; i < Naverage; i++) {
+    if (!average[i].Nlensobj) continue;
+    // off_t m = average[i].lensobjOffset;
+    // myAssert (lensobj[m].averef == i, "not sorted");
+    for (j = 0; j < average[i].Nlensobj - 1; j++, N++) {
+      // myAssert (lensobj[m+j+1].averef == i, "not sorted");
+      next_lensobj[N] = N + 1;
+      if (N >= Nlensobj) {
+	fprintf (stderr, "WARNING: N out of bounds (1)\n");
+      }
+    }
+    next_lensobj[N] = -1;
+    if (N >= Nlensobj) {
+      fprintf (stderr, "WARNING: N out of bounds (2)\n");
+    }
+
+    if (N >= Nlensobj) {
+      fprintf (stderr, "overflow in init_lensobj_links\n");
+      abort ();
+    }
+    N++;
+  }
+  return (next_lensobj);
+}
+
+/* construct lensobj links which are valid FOR THIS LOAD
+ * - if we have a full load, we will get links which can
+ *   be used by other programs (eg, relphot, etc)
+ * - if we have a partial load, the links are only valid
+ *   for that partial load
+ */ 
+
+off_t *build_lensobj_links (Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj) {
+
+  fprintf (stderr, "input is not sorted but contains lensobj -- trouble\n");
+  exit (2);
+
+# if (0)
+
+  off_t i, m, k, Nm, averef;
+  off_t *next_lensobj;
+
+  ALLOCATE (next_lensobj, off_t, Nlensobj);
+
+  /* reset the Nm, offset values for average */
+  for (i = 0; i < Naverage; i++) {
+    average[i].lensobjOffset = -1;
+    average[i].Nlensobj     =  0;
+  }
+
+  for (Nm = 0; Nm < Nlensobj; Nm++) {
+    averef = lensobj[Nm].averef;
+    m = average[averef].lensobjOffset;  
+    next_lensobj[Nm] = -1;
+
+    if (m == -1) { /* no links yet for source */
+      average[averef].lensobjOffset = Nm;
+      average[averef].Nlensobj     = 1;
+      continue;
+    }
+
+    for (k = 0; next_lensobj[m] != -1; k++) {
+      m = next_lensobj[m];
+      if (m >= Nlensobj) {
+	fprintf (stderr, "WARNING: m out of bounds (1)\n");
+      }
+    }
+
+    average[averef].Nlensobj = k + 2;
+    next_lensobj[m] = Nm;
+    if (m >= Nlensobj) {
+      fprintf (stderr, "WARNING: m out of bounds (2)\n");
+    }
+  }
+  return (next_lensobj);
+# endif
+}
+
+/* average[].lensobjOffset, average[].Nlensobj are valid within an addstar run */
+int add_lensobj_link (Average *average, off_t *next_lensobj, off_t Nlensobj, off_t NLENSOBJ) {
+
+  off_t k, m;
+
+  /* if we have trouble, check validity of next_lensobj[m] : m < Nlensobj */
+  m = average[0].lensobjOffset;  
+
+  for (k = 0; k < average[0].Nlensobj - 1; k++)  {
+    m = next_lensobj[m];
+    if (m >= NLENSOBJ) {
+      fprintf (stderr, "WARNING: m out of bounds (3)\n");
+    }
+  }
+
+  /* set up references */
+  next_lensobj[Nlensobj] = -1;
+  if (Nlensobj >= NLENSOBJ) {
+    fprintf (stderr, "WARNING: Nlensobj out of bounds (1)\n");
+  }
+
+  // if Nlensobj is 0, m may have been mis-set; add to the end
+  if ((average[0].Nlensobj == 0) || (m == -1)) {
+    average[0].lensobjOffset = Nlensobj;
+  } else {
+    next_lensobj[m] = Nlensobj;
+    if (m >= NLENSOBJ) {
+      fprintf (stderr, "WARNING: m out of bounds (4)\n");
+    }
+  }
+
+  return (TRUE);
+}
+
+Lensobj *sort_lensobj (Average *average, off_t Naverage, Lensobj *lensobj, off_t Nlensobj, off_t *next_lensobj) {
+
+  off_t i, k, n, np, N;
+  Lensobj *tmplensobj;
+
+  /* fix order of Lensobj (memory intensive, but fast) */
+  np = -1;
+  N = 0; 
+  ALLOCATE (tmplensobj, Lensobj, Nlensobj);
+  for (i = 0; i < Naverage; i++) {
+    if (!average[i].Nlensobj) continue;
+    n = average[i].lensobjOffset;
+    average[i].lensobjOffset = N;
+    int myObjID = average[i].objID;
+    for (k = 0; k < average[i].Nlensobj; k++, N++) {
+      if (n == -1) {
+	fprintf (stderr, "entry after %d has a problem\n", (int) np);
+	abort();
+      }
+      tmplensobj[N] = lensobj[n]; 
+      // myAssert (lensobj[n].averef == i, "error in averef");
+      myAssert ((lensobj[n].objID == myObjID) || (lensobj[n].objID == -1), "error in objID?");
+      // tmplensobj[N].averef = i;
+      np = n;
+      n = next_lensobj[n];
+    }
+  }
+  free (lensobj);
+  return (tmplensobj);
 }
 
@@ -406,5 +564,5 @@
 
   off_t i, j, N;
-  off_t *next_star;
+  off_t *next_starpar;
 
   if (!starpar) return NULL;
@@ -415,6 +573,6 @@
   // NOTE that is we choose DVO_SKIP_STARPAR, catalog.starpar is NULL.
   // this code will let merge_catalogs_old.c do nothing for starpar
-  ALLOCATE (next_star, off_t, Nstarpar);
-  if (!starpar) return next_star;
+  ALLOCATE (next_starpar, off_t, Nstarpar);
+  if (!starpar) return next_starpar;
 
   for (i = 0; i < Naverage; i++) {
@@ -424,10 +582,10 @@
     for (j = 0; j < average[i].Nstarpar - 1; j++, N++) {
       myAssert (starpar[m+j+1].averef == i, "not sorted");
-      next_star[N] = N + 1;
+      next_starpar[N] = N + 1;
       if (N >= Nstarpar) {
 	fprintf (stderr, "WARNING: N out of bounds (1)\n");
       }
     }
-    next_star[N] = -1;
+    next_starpar[N] = -1;
     if (N >= Nstarpar) {
       fprintf (stderr, "WARNING: N out of bounds (2)\n");
@@ -440,5 +598,5 @@
     N++;
   }
-  return (next_star);
+  return (next_starpar);
 }
 
@@ -453,8 +611,8 @@
 
   off_t i, m, k, Nm, averef;
-  off_t *next_star;
-
-  ALLOCATE (next_star, off_t, Nstarpar);
-  if (!starpar) return next_star;
+  off_t *next_starpar;
+
+  ALLOCATE (next_starpar, off_t, Nstarpar);
+  if (!starpar) return next_starpar;
 
   /* reset the Nm, offset values for average */
@@ -467,5 +625,5 @@
     averef = starpar[Nm].averef;
     m = average[averef].starparOffset;  
-    next_star[Nm] = -1;
+    next_starpar[Nm] = -1;
 
     if (m == -1) { /* no links yet for source */
@@ -475,6 +633,6 @@
     }
 
-    for (k = 0; next_star[m] != -1; k++) {
-      m = next_star[m];
+    for (k = 0; next_starpar[m] != -1; k++) {
+      m = next_starpar[m];
       if (m >= Nstarpar) {
 	fprintf (stderr, "WARNING: m out of bounds (1)\n");
@@ -483,22 +641,22 @@
 
     average[averef].Nstarpar = k + 2;
-    next_star[m] = Nm;
+    next_starpar[m] = Nm;
     if (m >= Nstarpar) {
       fprintf (stderr, "WARNING: m out of bounds (2)\n");
     }
   }
-  return (next_star);
+  return (next_starpar);
 }
 
 /* average[].starparOffset, average[].Nstarpar are valid within an addstar run */
-int add_star_link (Average *average, off_t *next_star, off_t Nstarpar, off_t NSTARPAR) {
+int add_starpar_link (Average *average, off_t *next_starpar, off_t Nstarpar, off_t NSTARPAR) {
 
   off_t k, m;
 
-  /* if we have trouble, check validity of next_star[m] : m < Nstarpar */
+  /* if we have trouble, check validity of next_starpar[m] : m < Nstarpar */
   m = average[0].starparOffset;  
 
   for (k = 0; k < average[0].Nstarpar - 1; k++)  {
-    m = next_star[m];
+    m = next_starpar[m];
     if (m >= NSTARPAR) {
       fprintf (stderr, "WARNING: m out of bounds (3)\n");
@@ -507,5 +665,5 @@
 
   /* set up references */
-  next_star[Nstarpar] = -1;
+  next_starpar[Nstarpar] = -1;
   if (Nstarpar >= NSTARPAR) {
     fprintf (stderr, "WARNING: Nstarpar out of bounds (1)\n");
@@ -516,5 +674,5 @@
     average[0].starparOffset = Nstarpar;
   } else {
-    next_star[m] = Nstarpar;
+    next_starpar[m] = Nstarpar;
     if (m >= NSTARPAR) {
       fprintf (stderr, "WARNING: m out of bounds (4)\n");
@@ -525,5 +683,5 @@
 }
 
-StarPar *sort_starpar (Average *average, off_t Naverage, StarPar *starpar, off_t Nstarpar, off_t *next_star) {
+StarPar *sort_starpar (Average *average, off_t Naverage, StarPar *starpar, off_t Nstarpar, off_t *next_starpar) {
 
   off_t i, k, n, np, N;
@@ -552,5 +710,5 @@
       tmpstarpar[N].averef = i;
       np = n;
-      n = next_star[n];
+      n = next_starpar[n];
     }
   }
@@ -566,5 +724,5 @@
 
   off_t i, j, N;
-  off_t *next_galp;
+  off_t *next_galphot;
 
   if (galphot) return NULL;
@@ -573,5 +731,5 @@
   N = 0;
 
-  ALLOCATE (next_galp, off_t, Ngalphot);
+  ALLOCATE (next_galphot, off_t, Ngalphot);
   for (i = 0; i < Naverage; i++) {
     if (!average[i].Ngalphot) continue;
@@ -580,10 +738,10 @@
     for (j = 0; j < average[i].Ngalphot - 1; j++, N++) {
       myAssert (galphot[m+j+1].averef == i, "not sorted");
-      next_galp[N] = N + 1;
+      next_galphot[N] = N + 1;
       if (N >= Ngalphot) {
 	fprintf (stderr, "WARNING: N out of bounds (1)\n");
       }
     }
-    next_galp[N] = -1;
+    next_galphot[N] = -1;
     if (N >= Ngalphot) {
       fprintf (stderr, "WARNING: N out of bounds (2)\n");
@@ -596,5 +754,5 @@
     N++;
   }
-  return (next_galp);
+  return (next_galphot);
 }
 
@@ -609,7 +767,7 @@
 
   off_t i, m, k, Nm, averef;
-  off_t *next_galp;
-
-  ALLOCATE (next_galp, off_t, Ngalphot);
+  off_t *next_galphot;
+
+  ALLOCATE (next_galphot, off_t, Ngalphot);
 
   /* reset the Nm, offset values for average */
@@ -622,5 +780,5 @@
     averef = galphot[Nm].averef;
     m = average[averef].galphotOffset;  
-    next_galp[Nm] = -1;
+    next_galphot[Nm] = -1;
 
     if (m == -1) { /* no links yet for source */
@@ -630,6 +788,6 @@
     }
 
-    for (k = 0; next_galp[m] != -1; k++) {
-      m = next_galp[m];
+    for (k = 0; next_galphot[m] != -1; k++) {
+      m = next_galphot[m];
       if (m >= Ngalphot) {
 	fprintf (stderr, "WARNING: m out of bounds (1)\n");
@@ -638,22 +796,22 @@
 
     average[averef].Ngalphot = k + 2;
-    next_galp[m] = Nm;
+    next_galphot[m] = Nm;
     if (m >= Ngalphot) {
       fprintf (stderr, "WARNING: m out of bounds (2)\n");
     }
   }
-  return (next_galp);
+  return (next_galphot);
 }
 
 /* average[].galphotOffset, average[].Ngalphot are valid within an addstar run */
-int add_galp_link (Average *average, off_t *next_galp, off_t Ngalphot, off_t NGALPHOT) {
+int add_galphot_link (Average *average, off_t *next_galphot, off_t Ngalphot, off_t NGALPHOT) {
 
   off_t k, m;
 
-  /* if we have trouble, check validity of next_galp[m] : m < Ngalphot */
+  /* if we have trouble, check validity of next_galphot[m] : m < Ngalphot */
   m = average[0].galphotOffset;  
 
   for (k = 0; k < average[0].Ngalphot - 1; k++)  {
-    m = next_galp[m];
+    m = next_galphot[m];
     if (m >= NGALPHOT) {
       fprintf (stderr, "WARNING: m out of bounds (3)\n");
@@ -662,5 +820,5 @@
 
   /* set up references */
-  next_galp[Ngalphot] = -1;
+  next_galphot[Ngalphot] = -1;
   if (Ngalphot >= NGALPHOT) {
     fprintf (stderr, "WARNING: Ngalphot out of bounds (1)\n");
@@ -671,5 +829,5 @@
     average[0].galphotOffset = Ngalphot;
   } else {
-    next_galp[m] = Ngalphot;
+    next_galphot[m] = Ngalphot;
     if (m >= NGALPHOT) {
       fprintf (stderr, "WARNING: m out of bounds (4)\n");
@@ -680,5 +838,5 @@
 }
 
-GalPhot *sort_galphot (Average *average, off_t Naverage, GalPhot *galphot, off_t Ngalphot, off_t *next_galp) {
+GalPhot *sort_galphot (Average *average, off_t Naverage, GalPhot *galphot, off_t Ngalphot, off_t *next_galphot) {
 
   off_t i, k, n, np, N;
@@ -704,5 +862,5 @@
       tmpgalphot[N].averef = i;
       np = n;
-      n = next_galp[n];
+      n = next_galphot[n];
     }
   }
Index: trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 39693)
+++ trunk/Ohana/src/dvomerge/src/dvomergeUpdate_catalogs.c	(revision 39926)
@@ -336,4 +336,5 @@
     if (SKIP_MEASURE)               { strextend (&command, "-skip-measure"); }
     if (SKIP_LENSING)               { strextend (&command, "-skip-lensing"); }
+    if (SKIP_LENSOBJ)               { strextend (&command, "-skip-lensobj"); }
     if (SKIP_GALPHOT)               { strextend (&command, "-skip-galphot"); }
     if (SKIP_STARPAR)               { strextend (&command, "-skip-starpar"); }
Index: trunk/Ohana/src/dvomerge/src/merge_catalogs_old.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/merge_catalogs_old.c	(revision 39693)
+++ trunk/Ohana/src/dvomerge/src/merge_catalogs_old.c	(revision 39926)
@@ -14,6 +14,6 @@
   double *X1, *Y1, *X2, *Y2;
   double dX, dY, dR;
-  off_t *N1, *N2, *next_meas, *next_lens, *next_star, *next_galp;
-  off_t Nave, NAVE, Nmeas, NMEAS, Nmatch, Nlens, NLENS, Nstar, NSTAR, Ngalp, NGALP;
+  off_t *N1, *N2, *next_measure, *next_lensing, *next_lensobj, *next_starpar, *next_galphot;
+  off_t Nave, NAVE, Nmeasure, NMEASURE, Nmatch, Nlensing, NLENSING, Nlensobj, NLENSOBJ, Nstarpar, NSTARPAR, Ngalphot, NGALPHOT;
   int NsecfiltIn;
   int NsecfiltOut;
@@ -51,8 +51,9 @@
   /* internal counters */
   Nmatch = 0;
-  NMEAS = Nmeas = output[0].Nmeasure;
-  NLENS = Nlens = output[0].Nlensing;
-  NSTAR = Nstar = output[0].Nstarpar;
-  NGALP = Ngalp = output[0].Ngalphot;
+  NMEASURE = Nmeasure = output[0].Nmeasure;
+  NLENSING = Nlensing = output[0].Nlensing;
+  NLENSOBJ = Nlensobj = output[0].Nlensobj;
+  NSTARPAR = Nstarpar = output[0].Nstarpar;
+  NGALPHOT = Ngalphot = output[0].Ngalphot;
 
   // current max obj ID for this catalog
@@ -116,13 +117,15 @@
     // this version is only valid if we have done a full catalog load, and if the catalog
     // is sorted while processed
-    next_meas = init_measure_links (output[0].average, Nave, output[0].measure, Nmeas);
-    next_lens = init_lensing_links (output[0].average, Nave, output[0].lensing, Nlens);
-    next_star = init_starpar_links (output[0].average, Nave, output[0].starpar, Nstar);
-    next_galp = init_galphot_links (output[0].average, Nave, output[0].galphot, Ngalp);
+    next_measure = init_measure_links (output[0].average, Nave, output[0].measure, Nmeasure);
+    next_lensing = init_lensing_links (output[0].average, Nave, output[0].lensing, Nlensing);
+    next_lensobj = init_lensobj_links (output[0].average, Nave, output[0].lensobj, Nlensobj);
+    next_starpar = init_starpar_links (output[0].average, Nave, output[0].starpar, Nstarpar);
+    next_galphot = init_galphot_links (output[0].average, Nave, output[0].galphot, Ngalphot);
   } else {
-    next_meas = build_measure_links (output[0].average, Nave, output[0].measure, Nmeas);
-    next_lens = build_lensing_links (output[0].average, Nave, output[0].lensing, Nlens);
-    next_star = build_starpar_links (output[0].average, Nave, output[0].starpar, Nstar);
-    next_galp = build_galphot_links (output[0].average, Nave, output[0].galphot, Ngalp);
+    next_measure = build_measure_links (output[0].average, Nave, output[0].measure, Nmeasure);
+    next_lensing = build_lensing_links (output[0].average, Nave, output[0].lensing, Nlensing);
+    next_lensobj = build_lensobj_links (output[0].average, Nave, output[0].lensobj, Nlensobj);
+    next_starpar = build_starpar_links (output[0].average, Nave, output[0].starpar, Nstarpar);
+    next_galphot = build_galphot_links (output[0].average, Nave, output[0].galphot, Ngalphot);
   }    
 
@@ -183,23 +186,28 @@
 
     /* make sure there is space for next Nmeasure entries */
-    if (Nmeas + input[0].average[N].Nmeasure >= NMEAS) {
-      NMEAS = Nmeas + input[0].average[N].Nmeasure + 1000;
-      REALLOCATE (next_meas, off_t, NMEAS);
-      REALLOCATE (output[0].measure, Measure, NMEAS);
-    }
-    if (Nlens + input[0].average[N].Nlensing >= NLENS) {
-      NLENS = Nlens + input[0].average[N].Nlensing + 1000;
-      REALLOCATE (next_lens, off_t, NLENS);
-      REALLOCATE (output[0].lensing, Lensing, NLENS);
-    }
-    if (Nstar + input[0].average[N].Nstarpar >= NSTAR) {
-      NSTAR = Nstar + input[0].average[N].Nstarpar + 1000;
-      REALLOCATE (next_star, off_t, NSTAR);
-      REALLOCATE (output[0].starpar, StarPar, NSTAR);
-    }
-    if (Ngalp + input[0].average[N].Ngalphot >= NGALP) {
-      NGALP = Ngalp + input[0].average[N].Ngalphot + 1000;
-      REALLOCATE (next_galp, off_t, NGALP);
-      REALLOCATE (output[0].galphot, GalPhot, NGALP);
+    if (Nmeasure + input[0].average[N].Nmeasure >= NMEASURE) {
+      NMEASURE = Nmeasure + input[0].average[N].Nmeasure + 1000;
+      REALLOCATE (next_measure, off_t, NMEASURE);
+      REALLOCATE (output[0].measure, Measure, NMEASURE);
+    }
+    if (Nlensing + input[0].average[N].Nlensing >= NLENSING) {
+      NLENSING = Nlensing + input[0].average[N].Nlensing + 1000;
+      REALLOCATE (next_lensing, off_t, NLENSING);
+      REALLOCATE (output[0].lensing, Lensing, NLENSING);
+    }
+    if (Nlensobj + input[0].average[N].Nlensobj >= NLENSOBJ) {
+      NLENSOBJ = Nlensobj + input[0].average[N].Nlensobj + 1000;
+      REALLOCATE (next_lensobj, off_t, NLENSOBJ);
+      REALLOCATE (output[0].lensobj, Lensobj, NLENSOBJ);
+    }
+    if (Nstarpar + input[0].average[N].Nstarpar >= NSTARPAR) {
+      NSTARPAR = Nstarpar + input[0].average[N].Nstarpar + 1000;
+      REALLOCATE (next_starpar, off_t, NSTARPAR);
+      REALLOCATE (output[0].starpar, StarPar, NSTARPAR);
+    }
+    if (Ngalphot + input[0].average[N].Ngalphot >= NGALPHOT) {
+      NGALPHOT = Ngalphot + input[0].average[N].Ngalphot + 1000;
+      REALLOCATE (next_galphot, off_t, NGALPHOT);
+      REALLOCATE (output[0].galphot, GalPhot, NGALPHOT);
     }
 
@@ -212,7 +220,7 @@
       if (REPLACE_TYCHO) {
 	int Minp =  input[0].average[N].measureOffset;
-	Nreplace = replace_tycho (&output[0].average[n], output[0].measure, next_meas, &input[0].average[N], &input[0].measure[Minp]);
+	Nreplace = replace_tycho (&output[0].average[n], output[0].measure, next_measure, &input[0].average[N], &input[0].measure[Minp]);
 	if (Nreplace == 6) {
-	  output[0].found_t[n] = Nmeas;
+	  output[0].found_t[n] = Nmeasure;
 	  i++;
 	  continue;
@@ -227,13 +235,13 @@
 	  // index to first measure for this object
 	  // XXX this does not support lensing, starpar, or galphot measurements
-	  if (replace_match (&output[0].average[n], output[0].measure, next_meas, &input[0].average[N], &input[0].measure[offset])) {
+	  if (replace_match (&output[0].average[n], output[0].measure, next_measure, &input[0].average[N], &input[0].measure[offset])) {
 	    continue;
 	  }
 	}
 	/* add to end of measurement list */
-	add_meas_link (&output[0].average[n], next_meas, Nmeas, NMEAS);
+	add_measure_link (&output[0].average[n], next_measure, Nmeasure, NMEASURE);
 	
 	// set the new measurements
-	output[0].measure[Nmeas] = input[0].measure[offset];
+	output[0].measure[Nmeasure] = input[0].measure[offset];
 
 	// old code: find R,D using average_in[0], the get offset relative to average_out[0].  no longer
@@ -241,27 +249,27 @@
 	// Rin = input[0].average[N].R - input[0].measure[offset].dR / 3600.0;
 	// Din = input[0].average[N].D - input[0].measure[offset].dD / 3600.0;
-	// output[0].measure[Nmeas].dR = 3600.0*(output[0].average[n].R - Rin);
-	// output[0].measure[Nmeas].dD = 3600.0*(output[0].average[n].D - Din);
-
-	output[0].measure[Nmeas].dbFlags  = 0;  // XXX why reset these?
-	output[0].measure[Nmeas].averef   = n;
-	output[0].measure[Nmeas].objID    = output[0].average[n].objID;
-	output[0].measure[Nmeas].catID    = output[0].catID;
-
-	assert (output[0].measure[Nmeas].averef < Nave);
-
-	// fprintf (stderr, "Nave : "OFF_T_FMT", Nmeas : "OFF_T_FMT", dR: %f, dD: %f, catID: %d\n",  n,  Nmeas, output[0].measure[Nmeas].dR, output[0].measure[Nmeas].dD, output[0].measure[i].catID);
-
-	float dRoff = dvoOffsetR(&output[0].measure[Nmeas], &output[0].average[n]);
+	// output[0].measure[Nmeasure].dR = 3600.0*(output[0].average[n].R - Rin);
+	// output[0].measure[Nmeasure].dD = 3600.0*(output[0].average[n].D - Din);
+
+	output[0].measure[Nmeasure].dbFlags  = 0;  // XXX why reset these?
+	output[0].measure[Nmeasure].averef   = n;
+	output[0].measure[Nmeasure].objID    = output[0].average[n].objID;
+	output[0].measure[Nmeasure].catID    = output[0].catID;
+
+	assert (output[0].measure[Nmeasure].averef < Nave);
+
+	// fprintf (stderr, "Nave : "OFF_T_FMT", Nmeasure : "OFF_T_FMT", dR: %f, dD: %f, catID: %d\n",  n,  Nmeasure, output[0].measure[Nmeasure].dR, output[0].measure[Nmeasure].dD, output[0].measure[i].catID);
+
+	float dRoff = dvoOffsetR(&output[0].measure[Nmeasure], &output[0].average[n]);
 
 	// rationalize R
 	if (dRoff > +180.0*3600.0) {
 	  // average on high end of boundary, move star up
-	  output[0].measure[Nmeas].R += 360.0;
+	  output[0].measure[Nmeasure].R += 360.0;
 	  dRoff -= 360.0*3600.0;
 	}
 	if (dRoff < -180.0*3600.0) {
 	  // average on low end of boundary, move star down
-	  output[0].measure[Nmeas].R -= 360.0;
+	  output[0].measure[Nmeasure].R -= 360.0;
 	  dRoff += 360.0*3600.0;
 	}
@@ -272,5 +280,5 @@
 	    fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
 		     output[0].average[n].R, output[0].average[n].D, 
-		     output[0].measure[Nmeas].R, output[0].measure[Nmeas].D,
+		     output[0].measure[Nmeasure].R, output[0].measure[Nmeasure].D,
 		     X1[i], X2[Jmin], Y1[i], Y2[Jmin]);
 	    // XXX abort on this? -- this is a bad failure...
@@ -278,5 +286,5 @@
 	}
 	output[0].average[n].Nmeasure ++;
-	Nmeas ++;
+	Nmeasure ++;
       }
     }
@@ -286,15 +294,33 @@
       for (Nin = 0; Nin < input[0].average[N].Nlensing; Nin++) {
 	/* add to end of lensing list */
-	add_lens_link (&output[0].average[n], next_lens, Nlens, NLENS);
+	add_lensing_link (&output[0].average[n], next_lensing, Nlensing, NLENSING);
 	
 	// set the new lensing
 	off_t lensoff = input[0].average[N].lensingOffset + Nin;
-	output[0].lensing[Nlens] = input[0].lensing[lensoff];
-
-	output[0].lensing[Nlens].averef   = n;
-	output[0].lensing[Nlens].objID    = output[0].average[n].objID;
-	output[0].lensing[Nlens].catID    = output[0].catID;
+	output[0].lensing[Nlensing] = input[0].lensing[lensoff];
+
+	output[0].lensing[Nlensing].averef   = n;
+	output[0].lensing[Nlensing].objID    = output[0].average[n].objID;
+	output[0].lensing[Nlensing].catID    = output[0].catID;
 	output[0].average[n].Nlensing ++;
-	Nlens ++;
+	Nlensing ++;
+      }
+    }
+
+    // if lensobj measurements exist, add them too
+    if (output[0].lensobj && !SKIP_LENSOBJ) {
+      for (Nin = 0; Nin < input[0].average[N].Nlensobj; Nin++) {
+	/* add to end of lensobj list */
+	add_lensobj_link (&output[0].average[n], next_lensobj, Nlensobj, NLENSOBJ);
+	
+	// set the new lensobj
+	off_t lensoff = input[0].average[N].lensobjOffset + Nin;
+	output[0].lensobj[Nlensobj] = input[0].lensobj[lensoff];
+
+	// output[0].lensobj[Nlensobj].averef   = n;
+	output[0].lensobj[Nlensobj].objID    = output[0].average[n].objID;
+	output[0].lensobj[Nlensobj].catID    = output[0].catID;
+	output[0].average[n].Nlensobj ++;
+	Nlensobj ++;
       }
     }
@@ -304,15 +330,15 @@
       for (Nin = 0; Nin < input[0].average[N].Nstarpar; Nin++) {
 	/* add to end of lensing list */
-	add_star_link (&output[0].average[n], next_star, Nstar, NSTAR);
+	add_starpar_link (&output[0].average[n], next_starpar, Nstarpar, NSTARPAR);
 	
 	// set the new starpar
 	off_t staroff = input[0].average[N].starparOffset + Nin;
-	output[0].starpar[Nstar] = input[0].starpar[staroff];
-
-	output[0].starpar[Nstar].averef   = n;
-	output[0].starpar[Nstar].objID    = output[0].average[n].objID;
-	output[0].starpar[Nstar].catID    = output[0].catID;
+	output[0].starpar[Nstarpar] = input[0].starpar[staroff];
+
+	output[0].starpar[Nstarpar].averef   = n;
+	output[0].starpar[Nstarpar].objID    = output[0].average[n].objID;
+	output[0].starpar[Nstarpar].catID    = output[0].catID;
 	output[0].average[n].Nstarpar ++;
-	Nstar ++;
+	Nstarpar ++;
       }
     }
@@ -322,15 +348,15 @@
       for (Nin = 0; Nin < input[0].average[N].Ngalphot; Nin++) {
 	/* add to end of galphot list */
-	add_galp_link (&output[0].average[n], next_galp, Ngalp, NGALP);
+	add_galphot_link (&output[0].average[n], next_galphot, Ngalphot, NGALPHOT);
 	
 	// set the new galphot
 	off_t galpoff = input[0].average[N].galphotOffset + Nin;
-	output[0].galphot[Ngalp] = input[0].galphot[galpoff];
-
-	output[0].galphot[Ngalp].averef   = n;
-	output[0].galphot[Ngalp].objID    = output[0].average[n].objID;
-	output[0].galphot[Ngalp].catID    = output[0].catID;
+	output[0].galphot[Ngalphot] = input[0].galphot[galpoff];
+
+	output[0].galphot[Ngalphot].averef   = n;
+	output[0].galphot[Ngalphot].objID    = output[0].average[n].objID;
+	output[0].galphot[Ngalphot].catID    = output[0].catID;
 	output[0].average[n].Ngalphot ++;
-	Ngalp ++;
+	Ngalphot ++;
       }
     }
@@ -373,8 +399,8 @@
     /* Nm is updated, but not written out in -update mode (for existing entries)
        Nm is recalculated in build_meas_links if loaded table is not sorted */
-    output[0].found_t[n] = Nmeas;
+    output[0].found_t[n] = Nmeasure;
     i++;
   }
-  // MARKTIME("find matched stars: %f sec for "OFF_T_FMT","OFF_T_FMT" stars ("OFF_T_FMT" meas)\n", dtime, Nstars, Nave, Nmeas);
+  // MARKTIME("find matched stars: %f sec for "OFF_T_FMT","OFF_T_FMT" stars ("OFF_T_FMT" meas)\n", dtime, Nstars, Nave, Nmeasure);
 
   /** incorporate unmatched image stars, if this star is in field of this catalog **/
@@ -384,23 +410,28 @@
 
     /* make sure there is space for next entry */
-    if (Nmeas + input[0].average[N].Nmeasure >= NMEAS) {
-      NMEAS = Nmeas + input[0].average[N].Nmeasure + 1000;
-      REALLOCATE (next_meas, off_t, NMEAS);
-      REALLOCATE (output[0].measure, Measure, NMEAS);
-    }
-    if (Nlens + input[0].average[N].Nlensing >= NLENS) {
-      NLENS = Nlens + input[0].average[N].Nlensing + 1000;
-      REALLOCATE (next_lens, off_t, NLENS);
-      REALLOCATE (output[0].lensing, Lensing, NLENS);
-    }
-    if (Nstar + input[0].average[N].Nstarpar >= NSTAR) {
-      NSTAR = Nstar + input[0].average[N].Nstarpar + 1000;
-      REALLOCATE (next_star, off_t, NSTAR);
-      REALLOCATE (output[0].starpar, StarPar, NSTAR);
-    }
-    if (Ngalp + input[0].average[N].Ngalphot >= NGALP) {
-      NGALP = Ngalp + input[0].average[N].Ngalphot + 1000;
-      REALLOCATE (next_galp, off_t, NGALP);
-      REALLOCATE (output[0].galphot, GalPhot, NGALP);
+    if (Nmeasure + input[0].average[N].Nmeasure >= NMEASURE) {
+      NMEASURE = Nmeasure + input[0].average[N].Nmeasure + 1000;
+      REALLOCATE (next_measure, off_t, NMEASURE);
+      REALLOCATE (output[0].measure, Measure, NMEASURE);
+    }
+    if (Nlensing + input[0].average[N].Nlensing >= NLENSING) {
+      NLENSING = Nlensing + input[0].average[N].Nlensing + 1000;
+      REALLOCATE (next_lensing, off_t, NLENSING);
+      REALLOCATE (output[0].lensing, Lensing, NLENSING);
+    }
+    if (Nlensobj + input[0].average[N].Nlensobj >= NLENSOBJ) {
+      NLENSOBJ = Nlensobj + input[0].average[N].Nlensobj + 1000;
+      REALLOCATE (next_lensobj, off_t, NLENSOBJ);
+      REALLOCATE (output[0].lensobj, Lensobj, NLENSOBJ);
+    }
+    if (Nstarpar + input[0].average[N].Nstarpar >= NSTARPAR) {
+      NSTARPAR = Nstarpar + input[0].average[N].Nstarpar + 1000;
+      REALLOCATE (next_starpar, off_t, NSTARPAR);
+      REALLOCATE (output[0].starpar, StarPar, NSTARPAR);
+    }
+    if (Ngalphot + input[0].average[N].Ngalphot >= NGALPHOT) {
+      NGALPHOT = Ngalphot + input[0].average[N].Ngalphot + 1000;
+      REALLOCATE (next_galphot, off_t, NGALPHOT);
+      REALLOCATE (output[0].galphot, GalPhot, NGALPHOT);
     }
     if (Nave >= NAVE) {
@@ -465,27 +496,27 @@
     /** add measurements for this input average object **/
     if (output[0].measure && !SKIP_MEASURE && input[0].average[N].Nmeasure) {
-      output[0].average[Nave].measureOffset  = Nmeas;
+      output[0].average[Nave].measureOffset  = Nmeasure;
       for (Nin = 0; Nin < input[0].average[N].Nmeasure; Nin ++) {
 	offset = input[0].average[N].measureOffset + Nin;
 	
 	// supply the measurments from this detection
-	output[0].measure[Nmeas]           = input[0].measure[offset];
+	output[0].measure[Nmeasure]           = input[0].measure[offset];
 	
 	// the following measure elements cannot be set until here:
-	output[0].measure[Nmeas].dbFlags  = 0;
-	output[0].measure[Nmeas].averef   = Nave;
-	output[0].measure[Nmeas].objID    = output[0].average[Nave].objID;
-	output[0].measure[Nmeas].catID    = output[0].catID;
+	output[0].measure[Nmeasure].dbFlags  = 0;
+	output[0].measure[Nmeasure].averef   = Nave;
+	output[0].measure[Nmeasure].objID    = output[0].average[Nave].objID;
+	output[0].measure[Nmeasure].catID    = output[0].catID;
 	
 	// as we add measurements, update Nmeasure to match
 	output[0].average[Nave].Nmeasure ++;
 
-	/* we set next[Nmeas] to -1 here, and update correctly below */
-	next_meas[Nmeas] = -1;
-	Nmeas ++;
+	/* we set next[Nmeasure] to -1 here, and update correctly below */
+	next_measure[Nmeasure] = -1;
+	Nmeasure ++;
       }
       int Ngroup = input[0].average[N].Nmeasure;
       for (j = 0; j < Ngroup - 1; j++) {
-	next_meas[Nmeas - Ngroup + j] = Nmeas - Ngroup + j + 1;
+	next_measure[Nmeasure - Ngroup + j] = Nmeasure - Ngroup + j + 1;
       }
     }
@@ -493,25 +524,51 @@
     /** add lensing for this input average object **/
     if (output[0].lensing && !SKIP_LENSING && input[0].average[N].Nlensing) {
-      output[0].average[Nave].lensingOffset  = Nlens;
+      output[0].average[Nave].lensingOffset  = Nlensing;
       for (Nin = 0; Nin < input[0].average[N].Nlensing; Nin ++) {
 	// supply the lensing values from this detection
 	off_t lensoff = input[0].average[N].lensingOffset + Nin;
-	output[0].lensing[Nlens]           = input[0].lensing[lensoff];
+	output[0].lensing[Nlensing]           = input[0].lensing[lensoff];
 
 	// the following lensing elements cannot be set until here:
-	output[0].lensing[Nlens].averef   = Nave;
-	output[0].lensing[Nlens].objID    = output[0].average[Nave].objID;
-	output[0].lensing[Nlens].catID    = output[0].catID;
+	output[0].lensing[Nlensing].averef   = Nave;
+	output[0].lensing[Nlensing].objID    = output[0].average[Nave].objID;
+	output[0].lensing[Nlensing].catID    = output[0].catID;
 
 	// as we add lensing, update Nlensing to match
 	output[0].average[Nave].Nlensing ++;
 
-	/* we set next[Nlens] to -1 here, and update correctly below */
-	next_lens[Nlens] = -1;
-	Nlens ++;
+	/* we set next[Nlensing] to -1 here, and update correctly below */
+	next_lensing[Nlensing] = -1;
+	Nlensing ++;
       }
       int Ngroup = input[0].average[N].Nlensing;
       for (j = 0; j < Ngroup - 1; j++) {
-	next_lens[Nlens - Ngroup + j] = Nlens - Ngroup + j + 1;
+	next_lensing[Nlensing - Ngroup + j] = Nlensing - Ngroup + j + 1;
+      }
+    }
+
+    /** add lensobj for this input average object **/
+    if (output[0].lensobj && !SKIP_LENSOBJ && input[0].average[N].Nlensobj) {
+      output[0].average[Nave].lensobjOffset  = Nlensobj;
+      for (Nin = 0; Nin < input[0].average[N].Nlensobj; Nin ++) {
+	// supply the lensobj values from this detection
+	off_t lensoff = input[0].average[N].lensobjOffset + Nin;
+	output[0].lensobj[Nlensobj]           = input[0].lensobj[lensoff];
+
+	// the following lensobj elements cannot be set until here:
+	// output[0].lensobj[Nlensobj].averef   = Nave;
+	output[0].lensobj[Nlensobj].objID    = output[0].average[Nave].objID;
+	output[0].lensobj[Nlensobj].catID    = output[0].catID;
+
+	// as we add lensobj, update Nlensobj to match
+	output[0].average[Nave].Nlensobj ++;
+
+	/* we set next[Nlensobj] to -1 here, and update correctly below */
+	next_lensobj[Nlensobj] = -1;
+	Nlensobj ++;
+      }
+      int Ngroup = input[0].average[N].Nlensobj;
+      for (j = 0; j < Ngroup - 1; j++) {
+	next_lensobj[Nlensobj - Ngroup + j] = Nlensobj - Ngroup + j + 1;
       }
     }
@@ -519,25 +576,25 @@
     /** add starpar for this input average object **/
     if (output[0].starpar && !SKIP_STARPAR && input[0].average[N].Nstarpar) {
-      output[0].average[Nave].starparOffset  = Nstar;
+      output[0].average[Nave].starparOffset  = Nstarpar;
       for (Nin = 0; Nin < input[0].average[N].Nstarpar; Nin ++) {
 	// supply the starpar values from this detection
 	off_t staroff = input[0].average[N].starparOffset + Nin;
-	output[0].starpar[Nstar]           = input[0].starpar[staroff];
+	output[0].starpar[Nstarpar]           = input[0].starpar[staroff];
 
 	// the following starpar elements cannot be set until here:
-	output[0].starpar[Nstar].averef   = Nave;
-	output[0].starpar[Nstar].objID    = output[0].average[Nave].objID;
-	output[0].starpar[Nstar].catID    = output[0].catID;
+	output[0].starpar[Nstarpar].averef   = Nave;
+	output[0].starpar[Nstarpar].objID    = output[0].average[Nave].objID;
+	output[0].starpar[Nstarpar].catID    = output[0].catID;
 
 	// as we add starpar, update Nstarpar to match
 	output[0].average[Nave].Nstarpar ++;
 
-	/* we set next[Nstar] to -1 here, and update correctly below */
-	next_star[Nstar] = -1;
-	Nstar ++;
+	/* we set next[Nstarpar] to -1 here, and update correctly below */
+	next_starpar[Nstarpar] = -1;
+	Nstarpar ++;
       }
       int Ngroup = input[0].average[N].Nstarpar;
       for (j = 0; j < Ngroup - 1; j++) {
-	next_star[Nstar - Ngroup + j] = Nstar - Ngroup + j + 1;
+	next_starpar[Nstarpar - Ngroup + j] = Nstarpar - Ngroup + j + 1;
       }
     }
@@ -545,25 +602,25 @@
     /** add galphot for this input average object **/
     if (output[0].galphot && !SKIP_GALPHOT && input[0].average[N].Ngalphot) {
-      output[0].average[Nave].galphotOffset  = Ngalp;
+      output[0].average[Nave].galphotOffset  = Ngalphot;
       for (Nin = 0; Nin < input[0].average[N].Ngalphot; Nin ++) {
 	// supply the galphot values from this detection
 	off_t galpoff = input[0].average[N].galphotOffset + Nin;
-	output[0].galphot[Ngalp]           = input[0].galphot[galpoff];
+	output[0].galphot[Ngalphot]           = input[0].galphot[galpoff];
 
 	// the following galphot elements cannot be set until here:
-	output[0].galphot[Ngalp].averef   = Nave;
-	output[0].galphot[Ngalp].objID    = output[0].average[Nave].objID;
-	output[0].galphot[Ngalp].catID    = output[0].catID;
+	output[0].galphot[Ngalphot].averef   = Nave;
+	output[0].galphot[Ngalphot].objID    = output[0].average[Nave].objID;
+	output[0].galphot[Ngalphot].catID    = output[0].catID;
 
 	// as we add galphot, update Ngalphot to match
 	output[0].average[Nave].Ngalphot ++;
 
-	/* we set next[Ngalp] to -1 here, and update correctly below */
-	next_galp[Ngalp] = -1;
-	Ngalp ++;
+	/* we set next[Ngalphot] to -1 here, and update correctly below */
+	next_galphot[Ngalphot] = -1;
+	Ngalphot ++;
       }
       int Ngroup = input[0].average[N].Ngalphot;
       for (j = 0; j < Ngroup - 1; j++) {
-	next_galp[Ngalp - Ngroup + j] = Ngalp - Ngroup + j + 1;
+	next_galphot[Ngalphot - Ngroup + j] = Ngalphot - Ngroup + j + 1;
       }
     }
@@ -575,8 +632,9 @@
 
   REALLOCATE (output[0].average, Average, Nave);
-  if (!SKIP_MEASURE) { REALLOCATE (output[0].measure, Measure, Nmeas); }
-  if (!SKIP_LENSING) { REALLOCATE (output[0].lensing, Lensing, Nlens); }
-  if (!SKIP_STARPAR) { REALLOCATE (output[0].starpar, StarPar, Nstar); }
-  if (!SKIP_GALPHOT) { REALLOCATE (output[0].galphot, GalPhot, Ngalp); }
+  if (!SKIP_MEASURE) { REALLOCATE (output[0].measure, Measure, Nmeasure); }
+  if (!SKIP_LENSING) { REALLOCATE (output[0].lensing, Lensing, Nlensing); }
+  if (!SKIP_LENSOBJ) { REALLOCATE (output[0].lensobj, Lensobj, Nlensobj); }
+  if (!SKIP_STARPAR) { REALLOCATE (output[0].starpar, StarPar, Nstarpar); }
+  if (!SKIP_GALPHOT) { REALLOCATE (output[0].galphot, GalPhot, Ngalphot); }
  
 # define NOSORT 0
@@ -585,8 +643,9 @@
   } else {
     output[0].sorted = TRUE;
-    if (!SKIP_MEASURE) { output[0].measure = sort_measure (output[0].average, Nave, output[0].measure, Nmeas, next_meas); }
-    if (!SKIP_LENSING) { output[0].lensing = sort_lensing (output[0].average, Nave, output[0].lensing, Nlens, next_lens); }
-    if (!SKIP_STARPAR) { output[0].starpar = sort_starpar (output[0].average, Nave, output[0].starpar, Nstar, next_star); }
-    if (!SKIP_GALPHOT) { output[0].galphot = sort_galphot (output[0].average, Nave, output[0].galphot, Ngalp, next_galp); }
+    if (!SKIP_MEASURE) { output[0].measure = sort_measure (output[0].average, Nave, output[0].measure, Nmeasure, next_measure); }
+    if (!SKIP_LENSING) { output[0].lensing = sort_lensing (output[0].average, Nave, output[0].lensing, Nlensing, next_lensing); }
+    if (!SKIP_LENSOBJ) { output[0].lensobj = sort_lensobj (output[0].average, Nave, output[0].lensobj, Nlensobj, next_lensobj); }
+    if (!SKIP_STARPAR) { output[0].starpar = sort_starpar (output[0].average, Nave, output[0].starpar, Nstarpar, next_starpar); }
+    if (!SKIP_GALPHOT) { output[0].galphot = sort_galphot (output[0].average, Nave, output[0].galphot, Ngalphot, next_galphot); }
   }
 
@@ -594,15 +653,17 @@
   output[0].objID    = objID; // new max value, save on catalog close
   output[0].Naverage = Nave;
-  if (!SKIP_MEASURE) { output[0].Nmeasure = Nmeas; }
-  if (!SKIP_LENSING) { output[0].Nlensing = Nlens; }
-  if (!SKIP_STARPAR) { output[0].Nstarpar = Nstar; }
-  if (!SKIP_GALPHOT) { output[0].Ngalphot = Ngalp; }
+  if (!SKIP_MEASURE) { output[0].Nmeasure = Nmeasure; }
+  if (!SKIP_LENSING) { output[0].Nlensing = Nlensing; }
+  if (!SKIP_LENSOBJ) { output[0].Nlensobj = Nlensobj; }
+  if (!SKIP_STARPAR) { output[0].Nstarpar = Nstarpar; }
+  if (!SKIP_GALPHOT) { output[0].Ngalphot = Ngalphot; }
   output[0].Nsecfilt_mem = Nave*NsecfiltOut;
-  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas, Nlens, Ngalp: "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT", ("OFF_T_FMT" matches)\n",  Nstars,  Nave,  Nmeas,  Nlens, Ngalp, Nmatch);
-
-  free (next_meas);
-  free (next_lens);
-  free (next_star);
-  free (next_galp);
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeasure, Nlensing, Ngalphot: "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT", ("OFF_T_FMT" matches)\n",  Nstars,  Nave,  Nmeasure,  Nlensing, Ngalphot, Nmatch);
+
+  free (next_measure);
+  free (next_lensing);
+  free (next_lensobj);
+  free (next_starpar);
+  free (next_galphot);
 
   free (X2);
@@ -625,5 +686,5 @@
    images have boundaries which are lines in pixels coords, but curve in RA and DEC
    
-   output[0].found_t[Ncat] but stars[Nstar].found
+   output[0].found_t[Ncat] but stars[Nstars].found
    
 */
Index: trunk/Ohana/src/fakeastro/Makefile
===================================================================
--- trunk/Ohana/src/fakeastro/Makefile	(revision 39693)
+++ trunk/Ohana/src/fakeastro/Makefile	(revision 39926)
@@ -53,5 +53,7 @@
 $(SRC)/match_fake_stars.$(ARCH).o \
 $(SRC)/fakeastro_2mass.$(ARCH).o \
+$(SRC)/fakeastro_gaia.$(ARCH).o \
 $(SRC)/make_2mass_measures.$(ARCH).o \
+$(SRC)/make_gaia_measures.$(ARCH).o \
 $(SRC)/remote_hosts.$(ARCH).o 
 
Index: trunk/Ohana/src/fakeastro/include/fakeastro.h
===================================================================
--- trunk/Ohana/src/fakeastro/include/fakeastro.h	(revision 39693)
+++ trunk/Ohana/src/fakeastro/include/fakeastro.h	(revision 39926)
@@ -8,5 +8,5 @@
 # define RESETTIME { gettimeofday (&startTimer, (void *) NULL); }
 
-typedef enum {OP_NONE, OP_GALAXY, OP_IMAGES, OP_2MASS} FakeastroOp;
+typedef enum {OP_NONE, OP_GALAXY, OP_IMAGES, OP_2MASS, OP_GAIA} FakeastroOp;
 
 typedef struct {
@@ -87,6 +87,8 @@
 int    VERBOSE;
 int    VERBOSE2;
-int    TESTING;
 int    ONE_BIG_CHIP;
+
+float  TEST_SCALE;
+char  *GALAXY_MODEL;
 
 int    FORCE;
@@ -101,7 +103,9 @@
 char   FAKEASTRO_REF_EPOCH[80];
 char   FAKEASTRO_2MASS_EPOCH[80];
+char   FAKEASTRO_GAIA_EPOCH[80];
 
 float  RADIUS;
 float  MAX_MAG_2MASS;
+float  MAX_MAG_GAIA;
 
 SkyRegion UserPatch;
@@ -198,2 +202,5 @@
 int fakeastro_2mass ();
 int make_2mass_measures (Catalog *catalog);
+
+int fakeastro_gaia ();
+int make_gaia_measures (Catalog *catalog);
Index: trunk/Ohana/src/fakeastro/src/ConfigInit.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/ConfigInit.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/ConfigInit.c	(revision 39926)
@@ -19,5 +19,5 @@
   // if (!ScanConfig (config, "ADDSTAR_RADIUS",         "%lf", 0, &ADDSTAR_RADIUS))   ADDSTAR_RADIUS = 1.0;
 
-  if ((FAKEASTRO_OP == OP_GALAXY) || (FAKEASTRO_OP == OP_2MASS)) {
+  if ((FAKEASTRO_OP == OP_GALAXY) || (FAKEASTRO_OP == OP_2MASS) || (FAKEASTRO_OP == OP_GAIA)) {
     // force CATDIR to be absolute (so parallel mode will work)
     GetConfig (config, "CATDIR",                 "%s",  0, CATDIR);
@@ -60,4 +60,7 @@
     strcpy (FAKEASTRO_2MASS_EPOCH, "2000/01/01,00:00:00"); // epoch of 2MASS astrometry
   }
+  if (!ScanConfig (config, "FAKEASTRO_GAIA_EPOCH", "%s", 0, FAKEASTRO_GAIA_EPOCH)) {
+    strcpy (FAKEASTRO_GAIA_EPOCH, "2015/01/01,00:00:00"); // epoch of GAIA astrometry
+  }
 
   /* set the default search radius */
@@ -76,5 +79,5 @@
 
   // OP_2MASS is adding detections to an existing db, the others require and empty db
-  if (FAKEASTRO_OP != OP_2MASS) {
+  if ((FAKEASTRO_OP != OP_2MASS) && (FAKEASTRO_OP != OP_GAIA)) {
     // check for existence of CATDIR
     struct stat filestat;
Index: trunk/Ohana/src/fakeastro/src/args.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/args.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/args.c	(revision 39926)
@@ -26,8 +26,22 @@
   }
 
-  TESTING = FALSE;
+  if ((N = get_argument (*argc, argv, "-gaia"))) {
+    remove_argument (N, argc, argv);
+    FAKEASTRO_OP = OP_GAIA;
+  }
+
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (*argc, argv, "-galaxy-model"))) {
+    remove_argument (N, argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("ROESER");
+
+  TEST_SCALE = 1.0;
   if ((N = get_argument (*argc, argv, "-testing"))) {
     remove_argument (N, argc, argv);
-    TESTING = TRUE;
+    TEST_SCALE = atof(argv[N]);
+    remove_argument (N, argc, argv);
   }
   ONE_BIG_CHIP = FALSE;
@@ -114,4 +128,11 @@
   }
 
+  MAX_MAG_GAIA = 21.0;
+  if ((N = get_argument (*argc, argv, "-gaia-limit"))) {
+    remove_argument (N, argc, argv);
+    MAX_MAG_GAIA = atof(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
   FORCE = FALSE;
   if ((N = get_argument (*argc, argv, "-force"))) {
@@ -250,4 +271,12 @@
   // }
 
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (*argc, argv, "-galaxy-model"))) {
+    remove_argument (N, argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("FEAST-HIPPARCOS");
+
   VERBOSE = VERBOSE2 = FALSE;
   if ((N = get_argument (*argc, argv, "-v"))) {
@@ -273,5 +302,6 @@
   fprintf (stderr, " additional options: \n");
   fprintf (stderr, "  -region RA RA DEC DEC\n");
-  fprintf (stderr, "  -catalog (ra) (dec)\n\n");
+  fprintf (stderr, "  -catalog (ra) (dec)\n");
+  fprintf (stderr, "  -testing (scale)\n\n");
   fprintf (stderr, "  -v\n");
   fprintf (stderr, "  -vv\n");
Index: trunk/Ohana/src/fakeastro/src/fakeastro.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/fakeastro.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/fakeastro.c	(revision 39926)
@@ -41,4 +41,10 @@
       exit (0);
 
+    case OP_GAIA:
+      fakeastro_gaia ();
+      /* make_gaia_measures()
+       */
+      exit (0);
+
     default:
       fprintf (stderr, "impossible!\n");
Index: trunk/Ohana/src/fakeastro/src/fakeastro_gaia.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/fakeastro_gaia.c	(revision 39926)
+++ trunk/Ohana/src/fakeastro/src/fakeastro_gaia.c	(revision 39926)
@@ -0,0 +1,57 @@
+# include "fakeastro.h"
+
+int fakeastro_gaia () {
+
+  INITTIME;
+
+  SkyTable *skyTable = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (skyTable, CATDIR, "cpt");
+
+  SkyList *skylist  = SkyListByPatch (skyTable, -1, &UserPatch);
+
+  Catalog catalog;
+
+  // load stars from database in these regions
+  int i;
+  for (i = 0; i < skylist->Nregions; i++) {
+    dvo_catalog_init (&catalog, TRUE);
+
+    // set the parameters which guide catalog open/load/create
+    dvo_catalog_init (&catalog, TRUE);
+    catalog.filename  = skylist[0].filename[i];
+    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  = DVO_LOAD_AVERAGE | DVO_LOAD_SECFILT | DVO_LOAD_MEASURE | DVO_LOAD_STARPAR;
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure reading catalog %s\n", catalog.filename);
+      exit (1);
+    }
+    if (!catalog.Naverage_disk) {
+	if (VERBOSE2) { fprintf (stderr, "no data in %s, skipping\n", catalog.filename); }
+	dvo_catalog_unlock (&catalog);
+	dvo_catalog_free (&catalog);
+	continue;
+    }
+
+    make_gaia_measures (&catalog);
+
+    SetProtect (TRUE);
+    if (!dvo_catalog_update (&catalog, VERBOSE)) {
+      fprintf (stderr, "ERROR: failure to update %s\n", catalog.filename);
+      exit (3);
+    }
+    SetProtect (FALSE);
+
+    if (!dvo_catalog_unlock (&catalog)) {
+      fprintf (stderr, "ERROR: failure to unlock %s\n", catalog.filename);
+      exit (2);
+    }
+    dvo_catalog_free (&catalog);
+    if (VERBOSE) MARKTIME ("save cpt: %f sec\n", dtime); RESETTIME; 
+  }
+
+  exit (0);
+}
+
+
Index: trunk/Ohana/src/fakeastro/src/initialize.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/initialize.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/initialize.c	(revision 39926)
@@ -17,6 +17,6 @@
 
   // XXX add to config?
-  if (!InitGalaxyModel ("ROESER")) {
-    fprintf (stderr, "failed to init galaxy model\n");
+  if (!InitGalaxyModel (GALAXY_MODEL)) {
+    fprintf (stderr, "failed to init galaxy model %s\n", GALAXY_MODEL);
     exit (2);
   }
@@ -30,6 +30,6 @@
 
   // XXX add to config?
-  if (!InitGalaxyModel ("ROESER")) {
-    fprintf (stderr, "failed to init galaxy model\n");
+  if (!InitGalaxyModel (GALAXY_MODEL)) {
+    fprintf (stderr, "failed to init galaxy model %s\n", GALAXY_MODEL);
     exit (2);
   }
Index: trunk/Ohana/src/fakeastro/src/make_fake_stars_catalog.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/make_fake_stars_catalog.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/make_fake_stars_catalog.c	(revision 39926)
@@ -116,4 +116,7 @@
     double dDsee = ohana_gaussdev_rnd (0.0, 1.0 / SN);
 
+    // XXX TEST
+    // dDsee = dRsee = 0.0;
+
     double dRoff = (dRpm + dRsee) / 3600.0;
     double dDoff = (dDpm + dDsee) / 3600.0;
Index: trunk/Ohana/src/fakeastro/src/make_fakestars.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/make_fakestars.c	(revision 39693)
+++ trunk/Ohana/src/fakeastro/src/make_fakestars.c	(revision 39926)
@@ -35,4 +35,6 @@
       // we can generate a distribution which is uniform on the sky, in which case
       // we can limit to the selected patch analyically
+
+      // note: r & z are generated in parsec
       r = pow(drand48(), 0.33333) * FAKEASTRO_RGAL;
       z = 0.0;
@@ -48,4 +50,5 @@
       int inPatch = FALSE;
       while (!inPatch) {
+	// note: r & z are generated in parsec
 	z = ohana_gaussdev_rnd (0.0, FAKEASTRO_ZGAL);
 	r = sqrt(drand48()) * FAKEASTRO_RGAL;
@@ -68,4 +71,5 @@
     // double y = r*sin(L);
 
+    // distance here is in parsec
     double distance = sqrt (SQ(r) + SQ(z));
 
@@ -74,5 +78,6 @@
 
     double uL_sol, uB_sol;
-    SolarMotionModel_radians(&uL_sol, &uB_sol, Lrad, Brad, distance);
+    SolarMotionModel_radians(&uL_sol, &uB_sol, Lrad, Brad, distance / 1000.0);
+    // note: SolarMotionModel wants distance in kpc
 
     double uL = uL_gal + uL_sol;
@@ -80,8 +85,6 @@
     
     // XXX: amplify motion to make tests easier:
-    if (TESTING) {
-      uL *= 100.0;
-      uB *= 100.0;
-    }
+    uL *= TEST_SCALE;
+    uB *= TEST_SCALE;
     
     double uR, uD;
Index: trunk/Ohana/src/fakeastro/src/make_gaia_measures.c
===================================================================
--- trunk/Ohana/src/fakeastro/src/make_gaia_measures.c	(revision 39926)
+++ trunk/Ohana/src/fakeastro/src/make_gaia_measures.c	(revision 39926)
@@ -0,0 +1,126 @@
+# include "fakeastro.h"
+
+// region corresponds to the catalog
+int make_gaia_measures (Catalog *catalog) {
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  Average *average = catalog->average;
+  SecFilt *secfilt = catalog->secfilt;
+  StarPar *starpar = catalog->starpar;
+  Measure *measure = catalog->measure;
+  
+  // we have starpar.R,D, which represent the true positions at the reference epoch, FAKEASTRO_REF_EPOCH
+  // the GAIA stars are generated at locations for the GAIA EPOCH
+  time_t timeRef = ohana_date_to_sec(FAKEASTRO_REF_EPOCH);
+  time_t tzero_gaia = ohana_date_to_sec(FAKEASTRO_GAIA_EPOCH);
+
+  // tzero, timeRef are in UNIX seconds, Toffset should be in years
+  double Toffset = (tzero_gaia - timeRef) / 365.25 / 86400.0;
+
+  // use photcode to get zero point
+  PhotCode *codeG = GetPhotcodebyName ("GAIA_G_DR1");
+
+  float ZP = MAX_MAG_GAIA + 6.5; // this is chosen to give stars at the limit a flux of 400.0 counts (crude, yes)
+  float SkyCts = 1000.0; // this is chosen to make SN @ limit ~ 10.0 (
+
+  int Nmeasure = catalog->Nmeasure;
+  int NMEASURE = catalog->Nmeasure;
+
+  int Nsec = 2; // i-band
+
+  int i;
+  for (i = 0; i < catalog->Naverage; i++) {
+
+    if (Nmeasure >= NMEASURE) {
+      NMEASURE = Nmeasure + 1000;
+      REALLOCATE (catalog[0].measure, Measure, NMEASURE);
+      measure = catalog[0].measure;
+    }
+
+    int Nstarpar = average[i].starparOffset;
+
+    // make a crude G-i color for now:
+    double G_PS1 = secfilt[i*Nsecfilt + Nsec].M; // make all stars have G-i = 1.0
+    if (G_PS1 > MAX_MAG_GAIA) continue; // only generate GAIA detections for objects with G_PS1 < 21.0
+
+    if (isnan(secfilt[i*Nsecfilt + Nsec].M)) {
+      // look for a non-NAN secfilt mag and just use that (it is not super important)
+      int ns;
+      for (ns = 0; ns < Nsecfilt; ns++) {
+	if (!isnan(secfilt[i*Nsecfilt + ns].M)) break;
+      }
+      if (ns == Nsecfilt) continue; // no non-nan
+
+      G_PS1 = secfilt[i*Nsecfilt + ns].M; // pretend secfilt.M = G
+      if (G_PS1 > MAX_MAG_GAIA) continue; // only generate GAIA detections for objects with G_PS1 < 21.0
+    }
+
+    double Minst = G_PS1 - ZP; 
+
+    double Counts = pow(10.0, -0.4*Minst);
+
+    double SN = Counts / sqrt(SkyCts + Counts);
+
+    // true position from src catalog
+    double Rtru = starpar[Nstarpar].R;
+    double Dtru = starpar[Nstarpar].D;
+
+    // observed position is scattered from true position by:
+    // * proper motion
+    // * gaussian scatter (~ seeing) 
+    double uR = starpar[Nstarpar].uRA; // starpar are in arcsec / year
+    double uD = starpar[Nstarpar].uDEC;
+    
+    // uR,uD in linear (arcsec / yr)
+    double dRpm = uR*Toffset;
+    double dDpm = uD*Toffset;
+
+    // uR,uD in linear arcsec
+    double dRsee = ohana_gaussdev_rnd (0.0, 0.01 / SN);
+    double dDsee = ohana_gaussdev_rnd (0.0, 0.01 / SN);
+
+    // XXX TEST
+    // dDsee = dRsee = 0.0;
+
+    double dRoff = (dRpm + dRsee) / 3600.0;
+    double dDoff = (dDpm + dDsee) / 3600.0;
+
+    double Robs = Rtru + dRoff / cos(Dtru*RAD_DEG);
+    double Dobs = Dtru + dDoff;
+
+    dvo_measure_init (&measure[Nmeasure]);
+
+    measure[Nmeasure].R = Robs;
+    measure[Nmeasure].D = Dobs;
+
+    measure[Nmeasure].M      = G_PS1;
+    measure[Nmeasure].dM     = 1.0 / SN;
+
+    measure[Nmeasure].Sky        = SkyCts;
+    measure[Nmeasure].dSky       = sqrt(SkyCts);
+    measure[Nmeasure].photFlags  = 0;
+    measure[Nmeasure].photFlags2 = 0;
+    measure[Nmeasure].airmass = 1.0;
+    measure[Nmeasure].az      = 0.0; // irrelevant
+    measure[Nmeasure].Mcal    = 0.0;
+    measure[Nmeasure].t       = tzero_gaia;
+    measure[Nmeasure].dt      = 0.0;
+    measure[Nmeasure].photcode = codeG->code;
+
+    measure[Nmeasure].averef   = i;
+    measure[Nmeasure].objID    = average[i].objID;
+    measure[Nmeasure].catID    = average[i].catID;
+
+    measure[Nmeasure].imageID = 0;
+
+    // This is may optionally be replaced by the internal sequence (see FilterStars.c)
+    measure[Nmeasure].detID      = 0;
+    Nmeasure ++;
+  }
+
+  if (VERBOSE) fprintf (stderr, "added %d gaia entries to %d stars\n",  (int) Nmeasure, (int) catalog->Naverage);
+
+  catalog->Nmeasure = Nmeasure;
+  return TRUE;
+}
Index: trunk/Ohana/src/kapa2/include/prototypes.h
===================================================================
--- trunk/Ohana/src/kapa2/include/prototypes.h	(revision 39693)
+++ trunk/Ohana/src/kapa2/include/prototypes.h	(revision 39926)
@@ -32,11 +32,11 @@
 void          DrawLabelsRaw       PROTO((Graphic *graphic, KapaGraphWidget *graph, int color));
 void	      DrawTextlines	  PROTO((KapaGraphWidget *graph));
-void          DrawConnect         PROTO((KapaGraphWidget *graph, Gobjects *objects));
-void          DrawHistogram       PROTO((KapaGraphWidget *graph, Gobjects *objects));
-int           DrawObjectN         PROTO((KapaGraphWidget *graph, Gobjects *objects));
-void          DrawPoints          PROTO((KapaGraphWidget *graph, Gobjects *objects));
-void          ClipLine            PROTO((double x0, double y0, double x1, double y1, double X0, double Y0, double X1, double Y1));
-void          DrawXErrors         PROTO((KapaGraphWidget *graph, Gobjects *objects));
-void          DrawYErrors         PROTO((KapaGraphWidget *graph, Gobjects *objects));
+void          DrawConnect         PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
+void          DrawHistogram       PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
+int           DrawObjectN         PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
+void          DrawPoints          PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
+void          ClipLine            PROTO((Graphic *graphic, double x0, double y0, double x1, double y1, double X0, double Y0, double X1, double Y1));
+void          DrawXErrors         PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
+void          DrawYErrors         PROTO((Graphic *graphic, KapaGraphWidget *graph, Gobjects *objects));
 void	      DrawTick		  PROTO((Graphic *graphic, Axis *axis, int P, TickMarkData *tick, int naxis));
 void	      AxisTickScale	  PROTO((Axis *axis, double *range, double *major, double *minor, int *nsignif));
@@ -115,4 +115,5 @@
 void          PSLabels            PROTO((KapaGraphWidget *graph, FILE *f));
 void	      PSTextlines	  PROTO((KapaGraphWidget *graph, FILE *f));
+int           PSObjectsN          PROTO((KapaGraphWidget *graph, Gobjects *objects, FILE *f));
 void          PSConnect           PROTO((KapaGraphWidget *graph, Gobjects *objects, FILE *f));
 void          PSHistogram         PROTO((KapaGraphWidget *graph, Gobjects *objects, FILE *f));
@@ -135,4 +136,5 @@
 void	      bDrawLabels	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
 void	      bDrawTextlines	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+int	      bDrawObjectsN	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
 void	      bDrawConnect	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
 void	      bDrawHistogram	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
Index: trunk/Ohana/src/kapa2/src/DrawFrame.c
===================================================================
--- trunk/Ohana/src/kapa2/src/DrawFrame.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/DrawFrame.c	(revision 39926)
@@ -12,4 +12,6 @@
 
   graphic = GetGraphic();
+
+  P = 0.5 * (1 + 0.25*graph[0].axis[0].lweight) * (hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy) + hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy));
 
   /* each axis is drawn independently, but ticks and labels are placed according to perpendicular distance. */
@@ -30,6 +32,6 @@
     dfy = graph[0].axis[i].dfy + 2*dy;
 
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-    P *= (1 + 0.25*lweight);
+    // P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    // P *= (1 + 0.25*lweight);
 
     XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CapNotLast, JoinMiter);
Index: trunk/Ohana/src/kapa2/src/DrawObjects.c
===================================================================
--- trunk/Ohana/src/kapa2/src/DrawObjects.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/DrawObjects.c	(revision 39926)
@@ -8,8 +8,4 @@
 # define FillCircle(X,Y,R) (XFillArc (graphic->display, graphic->window, graphic->gc, (int)(X-R), (int)(Y-R), abs(2*R+1), abs(2*R+1), 0, 23040))
 
-# define CONNECT 0
-# define HISTOGRAM 1
-# define POINTS 2
-
 # define XCENTER 0.0
 # define YCENTER 0.0
@@ -17,5 +13,6 @@
 # define JOINSTYLE JoinMiter
 
-static Graphic *graphic;
+// XXX this is not thread safe, but that is OK
+// static Graphic *graphic;
 
 /* draw all objects for this Graph */
@@ -24,14 +21,20 @@
   int i;
   
+  // the functions below use this global value
+  Graphic *graphic = GetGraphic();
+  
+  // this function calls all of the supporting Draw... functions below
   for (i = 0; i < graph[0].Nobjects; i++) {
     if (DEBUG) fprintf (stderr, "object: %d\n", i);
     if (DEBUG) fprintf (stderr, "Npts: %d\n", graph[0].objects[i].Npts);
-    DrawObjectN (graph, &graph[0].objects[i]);
+    DrawObjectN (graphic, graph, &graph[0].objects[i]);
   }    
+  XSetLineAttributes (graphic->display, graphic->gc, 0, LineSolid, CAPSTYLE, JOINSTYLE);
+  XSetForeground (graphic->display, graphic->gc, graphic->fore);
   return (TRUE);
 }
 
 /* Draw a specific object in the graph */
-int DrawObjectN (KapaGraphWidget *graph, Gobjects *object) {
+int DrawObjectN (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
   
   static char dot[2] = {2,3};
@@ -41,7 +44,4 @@
   int lweight;
   
-  // this function calls all of the supporting Draw... functions below
-  graphic = GetGraphic();
-  
   lweight = MAX (1, MIN (10, object[0].lweight));
 
@@ -58,23 +58,21 @@
   /* set line type */
   switch (object[0].ltype) {
-    case 0:
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CAPSTYLE, JOINSTYLE);
-      break;
-    case 1:
+    case KAPA_LINE_DOT:
       XSetDashes (graphic->display, graphic->gc, 1, dot, 2);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
-      break;
-    case 2:
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineDoubleDash, CAPSTYLE, JOINSTYLE);
+      break;
+    case KAPA_LINE_DASH_SHORT:
       XSetDashes (graphic->display, graphic->gc, 1, short_dash, 2);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
-      break;
-    case 3:
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineDoubleDash, CAPSTYLE, JOINSTYLE);
+      break;
+    case KAPA_LINE_DASH_LONG:
       XSetDashes (graphic->display, graphic->gc, 1, long_dash, 2);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
-      break;
-    case 4:
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineDoubleDash, CAPSTYLE, JOINSTYLE);
+      break;
+    case KAPA_LINE_DOT_DASH:
       XSetDashes (graphic->display, graphic->gc, 1, dot_dash, 4);
-      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineOnOffDash, CAPSTYLE, JOINSTYLE);
-      break;
+      XSetLineAttributes (graphic->display, graphic->gc, lweight, LineDoubleDash, CAPSTYLE, JOINSTYLE);
+      break;
+    case KAPA_LINE_SOLID:
     default:
       XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CAPSTYLE, JOINSTYLE);
@@ -88,29 +86,27 @@
 
   switch (object[0].style) {
-    case CONNECT: 
-      DrawConnect (graph, object);
-      break;
-    case HISTOGRAM:
-      DrawHistogram (graph, object);
-      break;
-    case POINTS:
-      DrawPoints (graph, object);
+    case KAPA_PLOT_CONNECT: 
+      DrawConnect (graphic, graph, object);
+      break;
+    case KAPA_PLOT_HISTOGRAM:
+      DrawHistogram (graphic, graph, object);
+      break;
+    case KAPA_PLOT_POINTS:
+    default:
+      DrawPoints (graphic, graph, object);
       break;
   }
     
   if (object[0].etype & 0x01) {
-    DrawYErrors (graph, object);
+    DrawYErrors (graphic, graph, object);
   }
   if (object[0].etype & 0x02) {
-    DrawXErrors (graph, object);
-  }
-
-  XSetLineAttributes (graphic->display, graphic->gc, 0, LineSolid, CAPSTYLE, JOINSTYLE);
-  XSetForeground (graphic->display, graphic->gc, graphic->fore);
+    DrawXErrors (graphic, graph, object);
+  }
   return (TRUE);
 }
 
 /******/
-void DrawConnect (KapaGraphWidget *graph, Gobjects *object) {
+void DrawConnect (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
   
   int i;
@@ -149,5 +145,5 @@
     sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
     
-    ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+    ClipLine (graphic, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
     /* DrawLine (sx0, sy0, sx1, sy1); */
     sx0 = sx1; sy0 = sy1;
@@ -156,5 +152,5 @@
 }
 
-void ClipLine (double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0) {
+void ClipLine (Graphic *graphic, double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0) {
 
   /* skip line segement if both points are beyond box */
@@ -212,5 +208,5 @@
 /* simplify the code abit by finding triplets, watch out for a histogram of 2 points */
 # if (1)
-void DrawHistogram (KapaGraphWidget *graph, Gobjects *object) {
+void DrawHistogram (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
 
   int i;
@@ -298,5 +294,5 @@
 # else 
 
-void DrawHistogram (KapaGraphWidget *graph, Gobjects *object) {
+void DrawHistogram (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
 
   int i;
@@ -407,5 +403,5 @@
 
 /******/
-void DrawPoints (KapaGraphWidget *graph, Gobjects *object) {
+void DrawPoints (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
 
   int i;
@@ -427,7 +423,5 @@
   by = byi + byj;
   
-  Graphic *graphic = GetGraphic();
-
-  /**** points are scaled by object.z ***/
+  /**** point sizes are scaled by object.size, colors by object.color ***/
   int scaleSize = (object[0].size < 0);
   int scaleColor = (object[0].color < 0);
@@ -437,315 +431,299 @@
   x = object[0].x; y = object[0].y; z = object[0].z;
 
-  if (object[0].ptype == 0) {	/* filled box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillRectangle (sx - D, sy - D, 2*D + 1, 2*D + 1);
-      }
+  switch (object[0].ptype) {
+    case KAPA_POINT_BOX_OPEN:	/* open box */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawRectangle (sx - D, sy - D, 2*D, 2*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CROSS: /* cross */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy, sx + D + 1, sy);
+	  DrawLine (sx, sy - D, sx, sy + D + 1);
+	}
+      }
+      break;
+    case KAPA_POINT_X:	/* x */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy + D, sx + D + 1, sy - D - 1);
+	  DrawLine (sx - D, sy - D, sx + D + 1, sy + D + 1);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID:	/* filled triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+
+	  XPoint points[4];
+	  points[0].x = sx - D;  points[0].y = sy + 0.58*D;  
+	  points[1].x = sx + D;  points[1].y = sy + 0.58*D;  
+	  points[2].x = sx;      points[2].y = sy - 1.15*D;  
+	  points[3].x = sx - D;  points[3].y = sy + 0.58*D;  
+	  XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID_DOWN: /* filled triangle (down) */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+
+	  XPoint points[4];
+	  points[0].x = sx - D;  points[0].y = sy - 0.58*D;  
+	  points[1].x = sx + D;  points[1].y = sy - 0.58*D;  
+	  points[2].x = sx;      points[2].y = sy + 1.15*D;  
+	  points[3].x = sx - D;  points[3].y = sy - 0.58*D;  
+	  XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
+	  DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
+	  DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN_DOWN:	/* upside-down open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D);
+	  DrawLine (sx + D, sy - 0.58*D, sx,     sy + 1.15*D);
+	  DrawLine (sx,     sy + 1.15*D, sx - D, sy - 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y:	/* Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx,     sy + 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y_DOWN:	/* upside-down Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx,     sy - 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_OPEN: /* 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_SOLID: /* filled 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillCircle (sx, sy, D);
+	  DrawCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_PENTAGON:	/* pentagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
+	  DrawLine (sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
+	  DrawLine (sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
+	  DrawLine (sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
+	  DrawLine (sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
+	}
+      }
+      break;
+    case KAPA_POINT_HEXAGON:	/* hexagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+
+	  DrawLine (sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
+	}
+      }
+      break;
+    case KAPA_POINT_PAIR_CONNECT: { /* connect pairs of points */
+      double X0 = graph[0].axis[0].fx;
+      double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+      double Y0 = graph[0].axis[1].fy;
+      double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+      for (i = 0; i + 1 < object[0].Npts; i+=2) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
+	if (!(finite(x[i+1]) && finite(y[i+1]))) continue;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx + XCENTER;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by + YCENTER;
+	ClipLine (graphic, sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
+      }
+      break;
     }
-  }
-  if (object[0].ptype == 1) {	/* open box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawRectangle (sx - D, sy - D, 2*D, 2*D);
-      }
-    }
-  }
-  if (object[0].ptype == 2) { /* cross */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy, sx + D + 1, sy);
-	DrawLine (sx, sy - D, sx, sy + D + 1);
-      }
-    }
-  }
-  if (object[0].ptype == 3) {	/* x */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy + D, sx + D + 1, sy - D - 1);
-	DrawLine (sx - D, sy - D, sx + D + 1, sy + D + 1);
-      }
-    }
-  }
-  if (object[0].ptype == 4) {	/* filled triangle */
-    XPoint points[4];
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	points[0].x = sx - D;  points[0].y = sy + 0.58*D;  
-	points[1].x = sx + D;  points[1].y = sy + 0.58*D;  
-	points[2].x = sx;      points[2].y = sy - 1.15*D;  
-	points[3].x = sx - D;  points[3].y = sy + 0.58*D;  
-	XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
-      }
-    }
-  }
-  if (object[0].ptype == 5) {	/* open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
-	DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
-	DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
-      }
-    }
-  }
-  if (object[0].ptype == 6) {	/* Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx, sy, sx - D, sy - 0.58*D);
-	DrawLine (sx, sy, sx + D, sy - 0.58*D);
-	DrawLine (sx, sy, sx,     sy + 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 7) {	/* 0 */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawCircle (sx, sy, D);
-      }
-    }
-  }
-  if (object[0].ptype == 8) {	/* pentagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
-	DrawLine (sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
-	DrawLine (sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
-	DrawLine (sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
-	DrawLine (sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
-      }
-    }
-  }
-  if (object[0].ptype == 9) {	/* hexagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
-	DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
-	DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
-
-	DrawLine (sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
-	DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
-	DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
-      }
-    }
-  }
-  if (object[0].ptype == 10) {	/* filled 0 */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillCircle (sx, sy, D);
-      }
-    }
-  }
-  if (object[0].ptype == 12) {	/* filled triangle (down) */
-    XPoint points[4];
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	points[0].x = sx - D;  points[0].y = sy - 0.58*D;  
-	points[1].x = sx + D;  points[1].y = sy - 0.58*D;  
-	points[2].x = sx;      points[2].y = sy + 1.15*D;  
-	points[3].x = sx - D;  points[3].y = sy - 0.58*D;  
-	XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
-      }
-    }
-  }
-  if (object[0].ptype == 14) {	/* upside-down filled triangle */
-    XPoint points[4];
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	points[0].x = sx - D;  points[0].y = sy - 0.58*D;  
-	points[1].x = sx + D;  points[1].y = sy - 0.58*D;  
-	points[2].x = sx;      points[2].y = sy + 1.15*D;  
-	points[3].x = sx - D;  points[3].y = sy - 0.58*D;  
-	XFillPolygon (graphic->display, graphic->window, graphic->gc, points, 4, Convex, CoordModeOrigin);
-      }
-    }
-  }
-  if (object[0].ptype == 15) {	/* upside-down open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D);
-	DrawLine (sx + D, sy - 0.58*D, sx,     sy + 1.15*D);
-	DrawLine (sx,     sy + 1.15*D, sx - D, sy - 0.58*D);
-      }
-    }
-  }
-  if (object[0].ptype == 16) {	/* upside-down Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy = x[i]*myi + y[i]*myj + by + YCENTER;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx, sy, sx - D, sy + 0.58*D);
-	DrawLine (sx, sy, sx + D, sy + 0.58*D);
-	DrawLine (sx, sy, sx,     sy - 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 100) {	/* connect a pair of points */
-
-    double X0 = graph[0].axis[0].fx;
-    double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
-    double Y0 = graph[0].axis[1].fy;
-    double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
-
-    for (i = 0; i + 1 < object[0].Npts; i+=2) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx1 = x[i]*mxi + y[i]*mxj + bx + XCENTER;
-      sy1 = x[i]*myi + y[i]*myj + by + YCENTER;
-      if (!(finite(x[i+1]) && finite(y[i+1]))) continue;
-      sx2 = x[i+1]*mxi + y[i+1]*mxj + bx + XCENTER;
-      sy2 = x[i+1]*myi + y[i+1]*myj + by + YCENTER;
-      ClipLine (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
-    }
+    case KAPA_POINT_BOX_SOLID:	/* filled box */
+    default:
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx + XCENTER;
+	sy = x[i]*myi + y[i]*myj + by + YCENTER;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    XSetForeground (graphic->display, graphic->gc, graphic->cmap[pixel].pixel);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillRectangle (sx - D, sy - D, 2*D + 1, 2*D + 1);
+	}
+      }
+      break;
   }
 }
     
 /******/
-void DrawXErrors (KapaGraphWidget *graph, Gobjects *object) {
+void DrawXErrors (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
   
   int i, bar, dz, ds, D;
@@ -800,9 +778,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy))) 
     {
-      ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+      ClipLine (graphic, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
       if (bar) {
 	sx10 = sy1 - sz;
 	sx11 = sy1 + sz;
-	ClipLine (sx1, sx10, sx1, sx11, X0, Y0, X1, Y1);
+	ClipLine (graphic, sx1, sx10, sx1, sx11, X0, Y0, X1, Y1);
       }
     }
@@ -819,9 +797,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+      ClipLine (graphic, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
       if (bar) {
 	sx10 = sy1 - sz;
 	sx11 = sy1 + sz;
-	ClipLine (sx1, sx10, sx1, sx11, X0, Y0, X1, Y1);
+	ClipLine (graphic, sx1, sx10, sx1, sx11, X0, Y0, X1, Y1);
       }
     }
@@ -830,5 +808,5 @@
     
 /******/
-void DrawYErrors (KapaGraphWidget *graph, Gobjects *object) {
+void DrawYErrors (Graphic *graphic, KapaGraphWidget *graph, Gobjects *object) {
 
   int i, bar, dz, ds, D;
@@ -883,9 +861,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+      ClipLine (graphic, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
       if (bar) {
 	sx10 = sx1 - sz;
 	sx11 = sx1 + sz;
-	ClipLine (sx10, sy1, sx11, sy1, X0, Y0, X1, Y1);
+	ClipLine (graphic, sx10, sy1, sx11, sy1, X0, Y0, X1, Y1);
       }
     }
@@ -904,9 +882,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      ClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+      ClipLine (graphic, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
       if (bar) {
 	sx10 = sx1 - sz;
 	sx11 = sx1 + sz;
-	ClipLine (sx10, sy1, sx11, sy1, X0, Y0, X1, Y1);
+	ClipLine (graphic, sx10, sy1, sx11, sy1, X0, Y0, X1, Y1);
       }
     }
Index: trunk/Ohana/src/kapa2/src/LoadObject.c
===================================================================
--- trunk/Ohana/src/kapa2/src/LoadObject.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/LoadObject.c	(revision 39926)
@@ -102,5 +102,8 @@
   if (DEBUG) fprintf (stderr, "loaded %d objects, using object %d\n", graph[0].objects[N].Npts, N);
 
-  if (USE_XWINDOW) DrawObjectN (graph, &graph[0].objects[graph[0].Nobjects-1]);
+  if (USE_XWINDOW) {
+    Graphic *graphic = GetGraphic();
+    DrawObjectN (graphic, graph, &graph[0].objects[graph[0].Nobjects-1]);
+  }
   FlushDisplay ();
 
Index: trunk/Ohana/src/kapa2/src/PSFrame.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PSFrame.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/PSFrame.c	(revision 39926)
@@ -11,4 +11,6 @@
 
   graphic = GetGraphic();
+
+  P = 0.5 * (1 + 0.25*graph[0].axis[0].lweight) * (hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy) + hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy));
 
   /* each axis is drawn independently */
@@ -30,6 +32,6 @@
     dfy = -graph[0].axis[i].dfy + 2*dy;
 
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-    P *= (1 + 0.25*lweight);
+    // P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    // P *= (1 + 0.25*lweight);
 
     fprintf (f, "%.1f setlinewidth\n", lweight);
Index: trunk/Ohana/src/kapa2/src/PSObjects.c
===================================================================
--- trunk/Ohana/src/kapa2/src/PSObjects.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/PSObjects.c	(revision 39926)
@@ -7,8 +7,9 @@
 # define FillCircle(X1,Y1,R) (fprintf (f, " %6.2f %6.2f %6.2f FC\n", (X1), (graphic->dy - Y1), (R)))
 # define FillTriangle(X1,Y1,X2,Y2, X3, Y3) (fprintf (f, " %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f TF\n", (X1), (graphic->dy-Y1), (X2), (graphic->dy-Y2), (X3), (graphic->dy-Y3)))
-# define CONNECT 0
-# define HISTOGRAM 1
-# define POINTS 2
-
+
+# define CAPSTYLE 1 /* CapButt */
+# define JOINSTYLE 0 /* JoinMiter */
+
+// XXX this is not thread safe, but that is OK
 static Graphic *graphic;
 
@@ -16,51 +17,70 @@
   
   int i;
-  double lweight;
-  static char dash[] = "5";
-  static char dot[] = "3";
-  
+  
+  // the functions below use this global value
   graphic = GetGraphic();
 
+  // this function calls all of the supporting Draw... functions below
   for (i = 0; i < graph[0].Nobjects; i++) {
-    switch (graph[0].objects[i].ltype) {
-    case 0:
-      break;
-    case 1:
-      fprintf (f, "[%s] 0 setdash\n", dash);
-      break;
-    case 2:
+    PSObjectsN (graph, &graph[0].objects[i], f);
+  }
+  // reset to default color and style
+  fprintf (f, "[] 0 setdash\n");
+  fprintf (f, "0.00 0.00 0.00 setrgbcolor\n");
+
+  return (TRUE);
+}
+
+int PSObjectsN (KapaGraphWidget *graph, Gobjects *object, FILE *f) {
+  
+  static char short_dash[] = "4 4";
+  static char long_dash[] = "8 8";
+  static char dot_dash[] = "2 4 4 4";
+  static char dot[] = "2 3";
+  
+  double lweight = MAX (0, MIN (10, object->lweight));
+  fprintf (f, "%.1f setlinewidth\n", lweight);
+  fprintf (f, "%d setlinecap %d setlinejoin\n", CAPSTYLE, JOINSTYLE);
+
+  switch (object->ltype) {
+    case KAPA_LINE_DOT:
       fprintf (f, "[%s] 0 setdash\n", dot);
       break;
+    case KAPA_LINE_DASH_SHORT:
+      fprintf (f, "[%s] 0 setdash\n", short_dash);
+      break;
+    case KAPA_LINE_DASH_LONG: 
+      fprintf (f, "[%s] 0 setdash\n", long_dash);
+      break;
+    case KAPA_LINE_DOT_DASH:
+      fprintf (f, "[%s] 0 setdash\n", dot_dash);
+      break;
+    case KAPA_LINE_SOLID: // no need to call 'setdash' as solid is the default
     default:
       break;
-    }
+  }
     
-    lweight = MAX (0, MIN (10, graph[0].objects[i].lweight));
-    fprintf (f, "%.1f setlinewidth\n", lweight);
-
-    if (graph[0].objects[i].color >= 0) {
-	fprintf (f, "%s setrgbcolor\n", KapaColorRGBString(graph[0].objects[i].color));
-    }
-
-    switch (graph[0].objects[i].style) {
-    case CONNECT: 
-      PSConnect (graph, &graph[0].objects[i], f);
-      break;
-    case HISTOGRAM:
-      PSHistogram (graph, &graph[0].objects[i], f);
-      break;
-    case POINTS:
-      PSPoints (graph, &graph[0].objects[i], f);
-      break;
-    }
-
-    if (graph[0].objects[i].etype & 0x01) {
-      PSYErrors (graph, &graph[0].objects[i], f);
-    }
-    if (graph[0].objects[i].etype & 0x02) {
-      PSXErrors (graph, &graph[0].objects[i], f);
-    }
-    fprintf (f, "[] 0 setdash\n");
-    fprintf (f, "0.00 0.00 0.00 setrgbcolor\n");
+  if (object->color >= 0) {
+    fprintf (f, "%s setrgbcolor\n", KapaColorRGBString(object->color));
+  }
+
+  switch (object->style) {
+    case KAPA_PLOT_CONNECT: 
+      PSConnect (graph, object, f);
+      break;
+    case KAPA_PLOT_HISTOGRAM: 
+      PSHistogram (graph, object, f);
+      break;
+    case KAPA_PLOT_POINTS: 
+    default:
+      PSPoints (graph, object, f);
+      break;
+  }
+
+  if (object->etype & 0x01) {
+    PSYErrors (graph, object, f);
+  }
+  if (object->etype & 0x02) {
+    PSXErrors (graph, object, f);
   }
   return (TRUE);
@@ -303,8 +323,7 @@
   }
 
-  // black, I think
   // fprintf (f, "0.00 0.00 0.00 setrgbcolor\n");
 
-  /**** points are scaled by object.z ***/
+  /**** point sizes are scaled by object.size, colors by object.color ***/
   int scaleSize = (object[0].size < 0);
   int scaleColor = (object[0].color < 0);
@@ -314,292 +333,281 @@
   x = object[0].x; y = object[0].y; z = object[0].z;
 
-  if (object[0].ptype == 0) {	/* filled box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillRectangle (sx, sy, 2*D, 2*D);
-      }
+  switch (object[0].ptype) {
+    case KAPA_POINT_BOX_OPEN:	/* open box */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawRectangle (sx, sy, 2*D, 2*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CROSS: /* cross */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy, sx + D, sy);
+	  DrawLine (sx, sy - D, sx, sy + D);
+	}
+      }
+      break;
+    case KAPA_POINT_X:	/* x */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx + D, sy - D, sx - D, sy + D);
+	  DrawLine (sx - D, sy - D, sx + D, sy + D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID:	/* filled triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillTriangle (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID_DOWN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillTriangle (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D);
+	  DrawLine (sx + D, sy - 0.58*D, sx,     sy + 1.15*D);
+	  DrawLine (sx,     sy + 1.15*D, sx - D, sy - 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN_DOWN:	/* upside-down open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
+	  DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
+	  DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y:	/* Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy + 0.58*D);
+	  DrawLine (sx, sy, sx,          sy - 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_Y_DOWN:	/* upside-down Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (sx, sy, sx,     sy + 1.15*D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_OPEN: /* 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_SOLID: /* filled 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillCircle (sx, sy, D);
+	}
+      }
+      break;
+    case KAPA_POINT_PENTAGON:	/* pentagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx + 0.00*D, sy + 1.00*D, sx + 0.95*D, sy + 0.31*D);
+	  DrawLine (sx + 0.95*D, sy + 0.31*D, sx + 0.58*D, sy - 0.81*D);
+	  DrawLine (sx + 0.58*D, sy - 0.81*D, sx - 0.58*D, sy - 0.81*D);
+	  DrawLine (sx - 0.58*D, sy - 0.81*D, sx - 0.95*D, sy + 0.31*D);
+	  DrawLine (sx - 0.95*D, sy + 0.31*D, sx + 0.00*D, sy + 1.00*D);
+	}
+      }
+      break;
+    case KAPA_POINT_HEXAGON:	/* hexagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (sx -      D, sy,               sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+
+	  DrawLine (sx +      D, sy,               sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
+	}
+      }
+      break;
+    case KAPA_POINT_PAIR_CONNECT: { /* connect pairs of points */
+      double X0 = graph[0].axis[0].fx;
+      double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+      double Y0 = graph[0].axis[1].fy;
+      double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+      for (i = 0; i + 1 < object[0].Npts; i+=2) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx1 = x[i]*mxi + y[i]*mxj + bx;
+	sy1 = x[i]*myi + y[i]*myj + by;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by;
+	ClipLinePS (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1, f);
+      }
+      break;
     }
-  }
-  if (object[0].ptype == 1) {	/* open box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawRectangle (sx, sy, 2*D, 2*D);
-      }
-    }
-  }
-  if (object[0].ptype == 2) { /* cross */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy, sx + D, sy);
-	DrawLine (sx, sy - D, sx, sy + D);
-      }
-    }
-  }
-  if (object[0].ptype == 3) {	/* x */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx + D, sy - D, sx - D, sy + D);
-	DrawLine (sx - D, sy - D, sx + D, sy + D);
-      }
-    }
-  }
-  if (object[0].ptype == 4) {	/* filled triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillTriangle (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 14) {	/* filled triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillTriangle (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 5) {	/* open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy - 0.58*D, sx + D, sy - 0.58*D);
-	DrawLine (sx + D, sy - 0.58*D, sx,     sy + 1.15*D);
-	DrawLine (sx,     sy + 1.15*D, sx - D, sy - 0.58*D);
-      }
-    }
-  }
-  if (object[0].ptype == 15) {	/* upside-down open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx - D, sy + 0.58*D, sx + D, sy + 0.58*D);
-	DrawLine (sx + D, sy + 0.58*D, sx,     sy - 1.15*D);
-	DrawLine (sx,     sy - 1.15*D, sx - D, sy + 0.58*D);
-      }
-    }
-  }
-  if (object[0].ptype == 6) {	/* Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx, sy, sx - D, sy + 0.58*D);
-	DrawLine (sx, sy, sx + D, sy + 0.58*D);
-	DrawLine (sx, sy, sx,          sy - 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 16) {	/* Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx, sy, sx - D, sy - 0.58*D);
-	DrawLine (sx, sy, sx + D, sy - 0.58*D);
-	DrawLine (sx, sy, sx,     sy + 1.15*D);
-      }
-    }
-  }
-  if (object[0].ptype == 7) {	/* 0 */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawCircle (sx, sy, D);
-      }
-    }
-  }
-  if (object[0].ptype == 8) {	/* pentagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx + 0.00*D, sy + 1.00*D, sx + 0.95*D, sy + 0.31*D);
-	DrawLine (sx + 0.95*D, sy + 0.31*D, sx + 0.58*D, sy - 0.81*D);
-	DrawLine (sx + 0.58*D, sy - 0.81*D, sx - 0.58*D, sy - 0.81*D);
-	DrawLine (sx - 0.58*D, sy - 0.81*D, sx - 0.95*D, sy + 0.31*D);
-	DrawLine (sx - 0.95*D, sy + 0.31*D, sx + 0.00*D, sy + 1.00*D);
-      }
-    }
-  }
-  if (object[0].ptype == 9) {	/* hexagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (sx -      D, sy,               sx - 0.50*D, sy + 0.87*D);
-	DrawLine (sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
-	DrawLine (sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
-
-	DrawLine (sx +      D, sy,               sx + 0.50*D, sy - 0.87*D);
-	DrawLine (sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
-	DrawLine (sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
-      }
-    }
-  }
-  if (object[0].ptype == 10) {	/* 0 */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillCircle (sx, sy, D);
-      }
-    }
-  }
-  if (object[0].ptype == 100) {	/* connect a pair of points */
-    double X0 = graph[0].axis[0].fx;
-    double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
-    double Y0 = graph[0].axis[1].fy;
-    double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
-
-    for (i = 0; i + 1 < object[0].Npts; i+=2) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx1 = x[i]*mxi + y[i]*mxj + bx;
-      sy1 = x[i]*myi + y[i]*myj + by;
-      sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
-      sy2 = x[i+1]*myi + y[i+1]*myj + by;
-      ClipLinePS (sx1, sy1, sx2, sy2, X0, Y0, X1, Y1, f);
-    }
-  }
-
+    case KAPA_POINT_BOX_SOLID:	/* filled box */
+    default:
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    fprintf (f, "%4.2f %4.2f %4.2f setrgbcolor\n", pixel1[pixel], pixel2[pixel], pixel3[pixel]);
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillRectangle (sx, sy, 2*D, 2*D);
+	}
+      }
+      break;
+  }
   free (pixel1);
   free (pixel2);
Index: trunk/Ohana/src/kapa2/src/bDrawFrame.c
===================================================================
--- trunk/Ohana/src/kapa2/src/bDrawFrame.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/bDrawFrame.c	(revision 39926)
@@ -11,4 +11,6 @@
 
   // don't need graphic, unlink DrawFrame
+
+  P = 0.5 * (1 + 0.25*graph[0].axis[0].lweight) * (hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy) + hypot (graph[0].axis[0].dfx, graph[0].axis[0].dfy));
 
   /* each axis is drawn independently */
@@ -28,6 +30,7 @@
     dfx = graph[0].axis[i].dfx + 2*dx;
     dfy = graph[0].axis[i].dfy + 2*dy;
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-    P *= (1 + 0.25*lweight);
+
+    // P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    // P *= (1 + 0.25*lweight);
 
     bDrawSetStyle (buffer, color, lweight, 0);
Index: trunk/Ohana/src/kapa2/src/bDrawObjects.c
===================================================================
--- trunk/Ohana/src/kapa2/src/bDrawObjects.c	(revision 39693)
+++ trunk/Ohana/src/kapa2/src/bDrawObjects.c	(revision 39926)
@@ -18,39 +18,42 @@
   
   int i;
-  int type;
-  int weight;
-  bDrawColor color;
-  bDrawColor black;
-  
+  
+  // the functions below use this global value
   graphic = GetGraphic();
 
-  black = KapaColorByName ("black");
+  // this function calls all of the supporting bDraw... functions below
   for (i = 0; i < graph[0].Nobjects; i++) {
-
-    weight = MAX (0, MIN (10, graph[0].objects[i].lweight));
-    type = graph[0].objects[i].ltype;    
-    color = graph[0].objects[i].color;
-    bDrawSetStyle (buffer, color, weight, type);
-
-    switch (graph[0].objects[i].style) {
-      case CONNECT: 
-	bDrawConnect (buffer, graph, &graph[0].objects[i]);
-	break;
-      case HISTOGRAM:
-	bDrawHistogram (buffer, graph, &graph[0].objects[i]);
-	break;
-      case POINTS:
-	bDrawPoints (buffer, graph, &graph[0].objects[i]);
-	break;
-    }
-
-    if (graph[0].objects[i].etype & 0x01) {
-      bDrawYErrors (buffer, graph, &graph[0].objects[i]);
-    }
-    if (graph[0].objects[i].etype & 0x02) {
-      bDrawXErrors (buffer, graph, &graph[0].objects[i]);
-    }
-  }
+    bDrawObjectsN (buffer, graph, &graph[0].objects[i]);
+  }
+  bDrawColor black = KapaColorByName ("black");
   bDrawSetStyle (buffer, black, 0, 0);
+  return (TRUE);
+}
+
+int bDrawObjectsN (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
+  
+  int weight = MAX (0, MIN (10, object->lweight));
+  bDrawSetStyle (buffer, object->color, weight, object->ltype);
+  
+  switch (object->style) {
+    case KAPA_PLOT_CONNECT: 
+      bDrawConnect (buffer, graph, object);
+      break;
+    case KAPA_PLOT_HISTOGRAM:
+      bDrawHistogram (buffer, graph, object);
+      break;
+    case KAPA_PLOT_POINTS:
+    default:
+      bDrawPoints (buffer, graph, object);
+      break;
+  }
+
+  if (object->etype & 0x01) {
+    bDrawYErrors (buffer, graph, object);
+  }
+  if (object->etype & 0x02) {
+    bDrawXErrors (buffer, graph, object);
+  }
+
   return (TRUE);
 }
@@ -298,354 +301,320 @@
   x = object[0].x; y = object[0].y; z = object[0].z;
 
-  if (object[0].ptype == 0) {	/* filled box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillRectangle (buffer, sx, sy, 2*D, 2*D);
-	// plot range saturated by bDrawRectFill
-      }
+  switch (object[0].ptype) {
+    case KAPA_POINT_BOX_OPEN:	/* open box */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawRectangle (buffer, sx, sy, 2*D, 2*D);
+	  // plot range saturated by bDrawRectOpen
+	}
+      }
+      break;
+    case KAPA_POINT_CROSS: /* cross */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx - D, sy, sx + D, sy);
+	  DrawLine (buffer, sx, sy - D, sx, sy + D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_X:	/* x */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx + D, sy - D, sx - D, sy + D);
+	  DrawLine (buffer, sx - D, sy - D, sx + D, sy + D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID:	/* filled triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  // FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	  FillTriangle (buffer, sx, sy + 0.58*D, D, -1.73*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_SOLID_DOWN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  // FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	  FillTriangle (buffer, sx, sy - 0.58*D, D, +1.73*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN:	/* open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  OpenTriangle (buffer, sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_TRIANGLE_OPEN_DOWN:	/* upside-down open triangle */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  OpenTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_Y:	/* Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx, sy, sx - D, sy - 0.58*D);
+	  DrawLine (buffer, sx, sy, sx + D, sy - 0.58*D);
+	  DrawLine (buffer, sx, sy, sx,     sy + 1.15*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_Y_DOWN:	/* upside-down Y */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx, sy, sx - D, sy + 0.58*D);
+	  DrawLine (buffer, sx, sy, sx + D, sy + 0.58*D);
+	  DrawLine (buffer, sx, sy, sx,     sy - 1.15*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_OPEN: /* 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawCircle (buffer, sx, sy, D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_CIRCLE_SOLID: /* filled 0 */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillCircle (buffer, sx, sy, D);
+	  // out-of-range points skipped by bDrawLineHorizontal
+	}
+      }
+      break;
+    case KAPA_POINT_PENTAGON:	/* pentagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
+	  DrawLine (buffer, sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
+	  DrawLine (buffer, sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
+	  DrawLine (buffer, sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
+	  DrawLine (buffer, sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_HEXAGON:	/* hexagon */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  DrawLine (buffer, sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
+	  DrawLine (buffer, sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
+	  DrawLine (buffer, sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
+	  DrawLine (buffer, sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
+	  DrawLine (buffer, sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
+	  DrawLine (buffer, sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
+	  // out-of-range points skipped by bDrawPoint
+	}
+      }
+      break;
+    case KAPA_POINT_PAIR_CONNECT: { /* connect pairs of points */
+
+      double X0 = graph[0].axis[0].fx;
+      double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+      double Y0 = graph[0].axis[1].fy;
+      double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
+
+      for (i = 0; i + 1 < object[0].Npts; i+=2) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx1 = x[i]*mxi + y[i]*mxj + bx;
+	sy1 = x[i]*myi + y[i]*myj + by;
+	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
+	sy2 = x[i+1]*myi + y[i+1]*myj + by;
+	bDrawClipLine (buffer, sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
+      }
+      break;
     }
-  }
-  if (object[0].ptype == 1) {	/* open box */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawRectangle (buffer, sx, sy, 2*D, 2*D);
-	// plot range saturated by bDrawRectOpen
-      }
-    }
-  }
-  if (object[0].ptype == 2) { /* cross */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx - D, sy, sx + D, sy);
-	DrawLine (buffer, sx, sy - D, sx, sy + D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 3) {	/* x */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx + D, sy - D, sx - D, sy + D);
-	DrawLine (buffer, sx - D, sy - D, sx + D, sy + D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 4) {	/* filled triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	// FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
-	FillTriangle (buffer, sx, sy + 0.58*D, D, -1.73*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 14) {	/* filled triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	// FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
-	FillTriangle (buffer, sx, sy - 0.58*D, D, +1.73*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 5) {	/* open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	OpenTriangle (buffer, sx - D, sy + 0.58*D, sx + D, sy + 0.58*D, sx, sy - 1.15*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 15) {	/* open triangle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	OpenTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 6) {	/* Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx, sy, sx - D, sy - 0.58*D);
-	DrawLine (buffer, sx, sy, sx + D, sy - 0.58*D);
-	DrawLine (buffer, sx, sy, sx,     sy + 1.15*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 16) {	/* Y */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx, sy, sx - D, sy + 0.58*D);
-	DrawLine (buffer, sx, sy, sx + D, sy + 0.58*D);
-	DrawLine (buffer, sx, sy, sx,     sy - 1.15*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 7) {	/* 0 */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawCircle (buffer, sx, sy, D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 8) {	/* pentagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx + 0.00*D, sy - 1.00*D, sx + 0.95*D, sy - 0.31*D);
-	DrawLine (buffer, sx + 0.95*D, sy - 0.31*D, sx + 0.58*D, sy + 0.81*D);
-	DrawLine (buffer, sx + 0.58*D, sy + 0.81*D, sx - 0.58*D, sy + 0.81*D);
-	DrawLine (buffer, sx - 0.58*D, sy + 0.81*D, sx - 0.95*D, sy - 0.31*D);
-	DrawLine (buffer, sx - 0.95*D, sy - 0.31*D, sx + 0.00*D, sy - 1.00*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 9) {	/* hexagon */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	DrawLine (buffer, sx -      D, sy,          sx - 0.50*D, sy + 0.87*D);
-	DrawLine (buffer, sx - 0.50*D, sy + 0.87*D, sx + 0.50*D, sy + 0.87*D);
-	DrawLine (buffer, sx + 0.50*D, sy + 0.87*D, sx +      D, sy);
-	DrawLine (buffer, sx +      D, sy,          sx + 0.50*D, sy - 0.87*D);
-	DrawLine (buffer, sx + 0.50*D, sy - 0.87*D, sx - 0.50*D, sy - 0.87*D);
-	DrawLine (buffer, sx - 0.50*D, sy - 0.87*D, sx -      D, sy);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 10) {	/* filled circle */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	FillCircle (buffer, sx, sy, D);
-	// out-of-range points skipped by bDrawLineHorizontal
-      }
-    }
-  }
-  if (object[0].ptype == 12) {	/* filled triangle (down) */
-    for (i = 0; i < object[0].Npts; i++) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx = x[i]*mxi + y[i]*mxj + bx;
-      sy = x[i]*myi + y[i]*myj + by;
-      if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
-	  (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
-      {
-	if (scaleColor) {
-	  if (!finite(z[i])) continue;
-	  int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
-	  buffer->bColor_R = pixel1[pixel];
-	  buffer->bColor_G = pixel2[pixel];
-	  buffer->bColor_B = pixel3[pixel];
-	}
-	D = scaleSize ? dz*z[i] : ds;
-	// FillTriangle (buffer, sx - D, sy - 0.58*D, sx + D, sy - 0.58*D, sx, sy + 1.15*D);
-	FillTriangle (buffer, sx, sy + 0.58*D, D, 1.73*D);
-	// out-of-range points skipped by bDrawPoint
-      }
-    }
-  }
-  if (object[0].ptype == 100) {	/* connect a pair of points */
-
-    double X0 = graph[0].axis[0].fx;
-    double X1 = graph[0].axis[0].fx + graph[0].axis[0].dfx;
-    double Y0 = graph[0].axis[1].fy;
-    double Y1 = graph[0].axis[1].fy + graph[0].axis[1].dfy;
-
-    for (i = 0; i + 1 < object[0].Npts; i+=2) {
-      if (!(finite(x[i]) && finite(y[i]))) continue;
-      sx1 = x[i]*mxi + y[i]*mxj + bx;
-      sy1 = x[i]*myi + y[i]*myj + by;
-      sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
-      sy2 = x[i+1]*myi + y[i+1]*myj + by;
-      bDrawClipLine (buffer, sx1, sy1, sx2, sy2, X0, Y0, X1, Y1);
-    }
-  }
-
+    case KAPA_POINT_BOX_SOLID:	/* filled box */
+      for (i = 0; i < object[0].Npts; i++) {
+	if (!(finite(x[i]) && finite(y[i]))) continue;
+	sx = x[i]*mxi + y[i]*mxj + bx;
+	sy = x[i]*myi + y[i]*myj + by;
+	if ((sx > graph[0].axis[0].fx) && (sx < graph[0].axis[0].fx + graph[0].axis[0].dfx) &&
+	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy)) {
+	  if (scaleColor) {
+	    if (!finite(z[i])) continue;
+	    int pixel = MIN (graphic->Npixels - 2, MAX (0, z[i]*(graphic->Npixels - 1)));
+	    buffer->bColor_R = pixel1[pixel];
+	    buffer->bColor_G = pixel2[pixel];
+	    buffer->bColor_B = pixel3[pixel];
+	  }
+	  D = scaleSize ? dz*z[i] : ds;
+	  FillRectangle (buffer, sx, sy, 2*D, 2*D);
+	  // plot range saturated by bDrawRectFill
+	}
+      }
+      break;
+  }
   free (pixel1);
   free (pixel2);
Index: trunk/Ohana/src/libdvo/include/dvo.h
===================================================================
--- trunk/Ohana/src/libdvo/include/dvo.h	(revision 39693)
+++ trunk/Ohana/src/libdvo/include/dvo.h	(revision 39926)
@@ -114,30 +114,33 @@
 /* Measure.flags values -- these values are 32 bit (as of PS1_V1) */
 typedef enum {
-  ID_MEAS_NOCAL          = 0x00000001,  // detection ignored for this analysis (photcode, time range) -- internal only 
-  ID_MEAS_POOR_PHOTOM    = 0x00000002,  // detection is photometry outlier					     	  
-  ID_MEAS_SKIP_PHOTOM    = 0x00000004,  // detection was ignored for photometry measurement			     	  
-  ID_MEAS_AREA           = 0x00000008,  // detection near image edge						     
-  ID_MEAS_POOR_ASTROM    = 0x00000010,  // detection is astrometry outlier					     	  
-  ID_MEAS_SKIP_ASTROM    = 0x00000020,  // detection was ignored for astrometry measurement			     	  
-  ID_MEAS_USED_OBJ       = 0x00000040,  // detection was used during update objects  
-  ID_MEAS_USED_CHIP      = 0x00000080,  // detection was used during update chips (XXX this probably does not make it into the db)
-  ID_MEAS_BLEND_MEAS     = 0x00000100,  // detection is within radius of multiple objects 
-  ID_MEAS_BLEND_OBJ      = 0x00000200,  // multiple detections within radius of object 
-  ID_MEAS_WARP_USED      = 0x00000400,  // measurement used to find mean warp photometry
-  ID_MEAS_UNMASKED_ASTRO = 0x00000800,  // measurement was not masked in final astrometry fit
-  ID_MEAS_BLEND_MEAS_X   = 0x00001000,  // detection is within radius of multiple objects across catalogs		     
-  ID_MEAS_ARTIFACT       = 0x00002000,  // detection is thought to be non-astronomical				     
-  ID_MEAS_SYNTH_MAG      = 0x00004000,  // magnitude is synthetic
-  ID_MEAS_PHOTOM_UBERCAL = 0x00008000,  // externally-supplied zero point from ubercal analysis
-  ID_MEAS_STACK_PRIMARY  = 0x00010000,  // this stack measurement is in the primary skycell
-  ID_MEAS_STACK_PHOT_SRC = 0x00020000,  // this measurement supplied the stack photometry
-  ID_MEAS_ICRF_QSO       = 0x00040000,  // this measurement is an ICRF reference position
-  ID_MEAS_IMAGE_EPOCH    = 0x00080000,  // this measurement is registered to the image epoch (not tied to ref catalog epoch)
-  ID_MEAS_PHOTOM_PSF     = 0x00100000,  // this measurement is used for the mean psf mag
-  ID_MEAS_PHOTOM_APER    = 0x00200000,  // this measurement is used for the mean ap mag
-  ID_MEAS_PHOTOM_KRON    = 0x00400000,  // this measurement is used for the mean kron mag
-  ID_MEAS_MASKED_PSF     = 0x01000000,  // this measurement is masked based on IRLS weights for mean psf mag
-  ID_MEAS_MASKED_APER    = 0x02000000,  // this measurement is masked based on IRLS weights for mean ap mag
-  ID_MEAS_MASKED_KRON    = 0x04000000,  // this measurement is masked based on IRLS weights for mean kron mag
+  ID_MEAS_NOCAL            = 0x00000001,  // detection ignored for this analysis (photcode, time range) -- internal only 
+  ID_MEAS_POOR_PHOTOM      = 0x00000002,  // detection is photometry outlier					     	  
+  ID_MEAS_SKIP_PHOTOM      = 0x00000004,  // detection was ignored for photometry measurement			     	  
+  ID_MEAS_AREA             = 0x00000008,  // detection near image edge						     
+  ID_MEAS_POOR_ASTROM      = 0x00000010,  // detection is astrometry outlier					     	  
+  ID_MEAS_SKIP_ASTROM      = 0x00000020,  // detection was ignored for astrometry measurement			     	  
+  ID_MEAS_USED_OBJ         = 0x00000040,  // detection was used during update objects  
+  ID_MEAS_USED_CHIP        = 0x00000080,  // detection was used during update chips (XXX this probably does not make it into the db)
+  ID_MEAS_BLEND_MEAS       = 0x00000100,  // detection is within radius of multiple objects 
+  ID_MEAS_BLEND_OBJ        = 0x00000200,  // multiple detections within radius of object 
+  ID_MEAS_WARP_USED        = 0x00000400,  // measurement used to find mean warp photometry
+  ID_MEAS_UNMASKED_ASTRO   = 0x00000800,  // measurement was not masked in final astrometry fit
+  ID_MEAS_BLEND_MEAS_X     = 0x00001000,  // detection is within radius of multiple objects across catalogs		     
+  ID_MEAS_ARTIFACT         = 0x00002000,  // detection is thought to be non-astronomical				     
+  ID_MEAS_SYNTH_MAG        = 0x00004000,  // magnitude is synthetic
+  ID_MEAS_PHOTOM_UBERCAL   = 0x00008000,  // externally-supplied zero point from ubercal analysis
+  ID_MEAS_STACK_PRIMARY    = 0x00010000,  // this stack measurement is in the primary skycell
+  ID_MEAS_STACK_PHOT_SRC   = 0x00020000,  // this measurement supplied the stack photometry
+  ID_MEAS_ICRF_QSO         = 0x00040000,  // this measurement is an ICRF reference position
+  ID_MEAS_IMAGE_EPOCH      = 0x00080000,  // this measurement is registered to the image epoch (not tied to ref catalog epoch)
+  ID_MEAS_PHOTOM_PSF       = 0x00100000,  // this measurement is used for the mean psf mag
+  ID_MEAS_PHOTOM_APER      = 0x00200000,  // this measurement is used for the mean ap mag
+  ID_MEAS_PHOTOM_KRON      = 0x00400000,  // this measurement is used for the mean kron mag
+  ID_MEAS_MASKED_PSF       = 0x01000000,  // this measurement is masked based on IRLS weights for mean psf mag
+  ID_MEAS_MASKED_APER      = 0x02000000,  // this measurement is masked based on IRLS weights for mean ap mag
+  ID_MEAS_MASKED_KRON      = 0x04000000,  // this measurement is masked based on IRLS weights for mean kron mag
+  ID_MEAS_OBJECT_HAS_2MASS = 0x10000000,  // measurement comes from an object with 2mass data
+  ID_MEAS_OBJECT_HAS_GAIA  = 0x20000000,  // measurement comes from an object with gaia data
+  ID_MEAS_OBJECT_HAS_TYCHO = 0x40000000,  // measurement comes from an object with tycho data
 } DVOMeasureFlags;
 
@@ -233,4 +236,10 @@
   ID_SECF_STACK_BESTDET = 0x00008000, // PS1 stack best measurement is a detection (not forced)
   ID_SECF_STACK_PRIMDET = 0x00010000, // PS1 stack primary measurement is a detection (not forced)
+
+  ID_SECF_HAS_SDSS      = 0x00100000, // this photcode has SDSS photometry
+  ID_SECF_HAS_HSC       = 0x00200000, // this photcode has HSC  photometry
+  ID_SECF_HAS_CFH       = 0x00400000, // this photcode has CFH  photometry (mostly Megacam)
+  ID_SECF_HAS_DES       = 0x00800000, // this photcode has DES  photometry
+
   ID_SECF_OBJ_EXT       = 0x01000000, // extended in this band
 
Index: trunk/Ohana/src/libdvo/src/ImageMetadataSelection.c
===================================================================
--- trunk/Ohana/src/libdvo/src/ImageMetadataSelection.c	(revision 39693)
+++ trunk/Ohana/src/libdvo/src/ImageMetadataSelection.c	(revision 39926)
@@ -59,4 +59,6 @@
 }
 
+// note that this function is called by the dvo clients and uses the 'metadata' table
+// generated by the dvo shell for the mosaic images only.
 Coords *MatchMosaicMetadata (unsigned int imageID) { 
 
@@ -73,4 +75,6 @@
   mosaic.crval2 = image[m].crval2;
 
+  // note that image->theta is calculated based on pc1_1, pc1_2 when the metadata file is
+  // generated
   mosaic.pc1_1 =  cos(RAD_DEG*image[m].theta);
   mosaic.pc1_2 =  sin(RAD_DEG*image[m].theta);
Index: trunk/Ohana/src/libdvo/src/coordops.c
===================================================================
--- trunk/Ohana/src/libdvo/src/coordops.c	(revision 39693)
+++ trunk/Ohana/src/libdvo/src/coordops.c	(revision 39926)
@@ -84,4 +84,5 @@
 
   /** extra polynomial terms **/
+  // for ZPN, these are used to modify the radial distance and not the X,Y coords
   if ((coords[0].Npolyterms > 1) && (proj != PROJ_ZPN)) {
     X2 = X*X;
@@ -126,5 +127,7 @@
     if (proj == PROJ_WRP) {
       if (!coords->mosaic) {
-	myAbort ("missing mosaic element");
+	// myAbort ("missing mosaic element");
+	*ra  = L;
+	*dec = M;
 	return (FALSE);
       }
@@ -157,8 +160,17 @@
 	  ctht = 0.0;
 	} else {
-	  T = DEG_RAD / R;
-	  stht =   T / sqrt ( 1.0 + T*T);
-	  ctht = 1.0 / sqrt ( 1.0 + T*T);
+	  // T = DEG_RAD / R; // T in 1/radians
+	  // stht =   T / sqrt ( 1.0 + T*T);
+	  // ctht = 1.0 / sqrt ( 1.0 + T*T);
+
+	  T = RAD_DEG * R;
+	  stht = 1.0 / sqrt ( 1.0 + T*T);
+	  ctht =   T / sqrt ( 1.0 + T*T);
 	}
+	break;
+      case PROJ_SIN:
+	// R = (180/pi) cos (theta)
+	ctht = RAD_DEG * R;
+	stht = sqrt (1 - ctht*ctht);
 	break;
       case PROJ_STG:
@@ -167,9 +179,4 @@
 	ctht = sqrt (1 - stht*stht);
 	break;
-      case PROJ_SIN:
-	// R = (180/pi) cos (theta)
-	ctht = RAD_DEG * R;
-	stht = sqrt (1 - ctht*ctht);
-	break;
       case PROJ_ARC:
 	// R = 90 - theta (degrees)
@@ -177,36 +184,4 @@
 	stht = cos (RAD_DEG * R);
 	break;
-
-      case PROJ_ZPN:
-	// R = 90 - theta (degrees)
-	// this is wrong because we are ignoring the distortion
-	// XXX For now, just solve for terms up to n = 3
-
-	// Ro = (pi/180)(90 - theta)
-	// R = (180/pi)sum (P_i R^i)
-
-	if (UKIRT_ONLY) {
-	  double Ro = RAD_DEG * R;
-	  double P1 = coords[0].polyterms[0][1];
-	  double P3 = coords[0].polyterms[0][3];
-
-	  // find the roots of f(gamma) = P1 gamma + P3 gamma^3 - Ro
-	  // starting guess for gamma is Ro / P1
-	  double gamma = Ro / P1;
-
-	  int i;
-	  for (i = 0; i < 5; i++) {
-	    double F = P1*gamma + P3*gamma*gamma*gamma - Ro;
-	    double dFdgamma = P1 + 3.0*P3*gamma*gamma;
-
-	    double gamma_new = gamma - F / dFdgamma;
-	    gamma = gamma_new;
-	  }
-	  
-	  double theta = 90.0 - gamma * DEG_RAD ;
-	  ctht = cos (RAD_DEG * theta);
-	  stht = sin (RAD_DEG * theta);
-	  break;
-	}
 
       case PROJ_ZEA:
@@ -220,4 +195,51 @@
 	ctht = sqrt (1 - stht*stht);
 	break;
+
+      case PROJ_ZPN:
+
+	// the forward projection is:
+	// theta = atan2(stht, ctht)
+	// gamma = (pi/2 - theta) : theta in radians
+	// Ro = sum (P_i gamma^i)
+	// R  = (180/pi) Ro
+
+	// given R, we need to find theta:
+	// Ro = R * (pi / 180) = sum (P_i gamma^i)
+	// solve sum (P_i gamma^i) - Ro = 0 using Newton-Raphson
+
+	// use Ro to get a guess for gamma and iterate
+
+	{
+	  double Ro = RAD_DEG * R;
+	  
+	  // find the roots of f(gamma) - Ro = 0
+	  // starting guess for gamma is (Ro - P0) / P1
+	  double gamma = (Ro - coords[0].polyterms[0][0]) / coords[0].polyterms[1][0];
+	  
+	  int iter;
+	  for (iter = 0; iter < 5; iter++) {
+	    
+	    double Rc = 0.0; // this will hold the ander 
+	    double dR = 0.0;
+	    for (int i = coords[0].Npolyterms - 1; i > 1; i--) {
+	      double Pi = (i < 7) ? coords[0].polyterms[i][0] : coords[0].polyterms[i-7][1];
+	      Rc = (Rc + Pi)*gamma;
+	      dR = (dR + i*Pi)*gamma;
+	    }
+	    double P0 = coords[0].polyterms[0][0];
+	    double P1 = coords[0].polyterms[1][0];
+	    Rc = (Rc + P1)*gamma + P0;
+	    dR = (dR + P1);
+
+	    double gamma_new = gamma - (Rc - Ro) / dR;
+	    gamma = gamma_new;
+	  }
+	  
+	  double theta = 90.0 - gamma * DEG_RAD ;
+	  ctht = cos (RAD_DEG * theta);
+	  stht = sin (RAD_DEG * theta);
+	  break;
+	}
+
       default:
 	return (FALSE);
@@ -354,32 +376,30 @@
 
       case PROJ_ZPN:
+	// the forward projection is:
+	// theta = atan2(stht, ctht)
+	// gamma = (pi/2 - theta) : theta in radians
+	// Ro = sum (P_i gamma^i)
+	// R  = (180/pi) Ro
+
 	// Ro = (pi/180)(90 - theta)
 	// R = (180/pi)sum (P_i R^i)
+
+	// is ZPN defined for Npolyterms = 0 or 1?
+
 	ctht = hypot(sphi, cphi);
 	theta = atan2 (stht, ctht);
 
-	double Rc;
-	if (UKIRT_ONLY) {
-	  double P1 = coords[0].polyterms[0][1];
-	  double P3 = coords[0].polyterms[0][3];
-	  double gamma = RAD_DEG * (90 - DEG_RAD * theta);
-	  Rc = P1*gamma + P3*gamma*gamma*gamma;
-	} else {
-	  double Ro = RAD_DEG * (90 - DEG_RAD * theta);
-
-	  // i = 0 .. Npolyterms - 1 (1 <= Npolyterms <= 21)
-	  i = coords[0].Npolyterms - 1;
-	  Rc = 0.0;
-	  while (i > 0) {
-	    if (i < 7) {
-	      Rc = (Rc + coords[0].polyterms[0][i])*Ro;
-	    } else {
-	      Rc = (Rc + coords[0].polyterms[1][i-7])*Ro;
-	    }
-	    i --;
-	  }
-	  Rc += coords[0].polyterms[0][i];
+	double Ro;
+	double gamma = M_PI_2 - theta;
+
+	// i = 0 .. Npolyterms - 1 (1 <= Npolyterms <= 21)
+	Ro = 0.0;
+	for (i = coords[0].Npolyterms - 1; i > 0; i --) {
+	  double Pi = (i < 7) ? coords[0].polyterms[i][0] : coords[0].polyterms[i-7][1];
+	  Ro = (Ro + Pi)*gamma;
 	}
-	Rc = DEG_RAD * Rc;
+	Ro += coords[0].polyterms[0][0];
+
+	Rc = DEG_RAD * Ro;
 
 	*L = (ctht == 0.0) ? 0.0 : +Rc * sphi / ctht ;
@@ -609,7 +629,9 @@
 enum {COORD_TYPE_NONE, COORD_TYPE_PC, COORD_TYPE_ROT, COORD_TYPE_CD, COORD_TYPE_LIN};
 
+int GetRadialZPN (Coords *coords, Header *header);
+
 int GetCoords (Coords *coords, Header *header) {
   
-  int i, status, status1, status2, itmp, Polynomial, Polyterm;
+  int status, status1, status2, itmp, Polynomial, Polyterm;
   double Lambda, rotate, rotate1, rotate2, scale;
   double equinox;
@@ -666,8 +688,16 @@
       status &= gfits_scan (header, "PC002002", "%f",  1, &coords[0].pc2_2);
 
+      ctype = &coords[0].ctype[4];
+
+      // read the ZPN coeffients PV2_i (i = 0 < 14)
+      // ZPN is inconsistent with the other Polynomial types
+      if (!strcmp (ctype, "-ZPN")) { 
+	GetRadialZPN (coords, header);
+	break;
+      }
+
       /* set NPLYTERM based on header.  if NPLYTERM is missing, it should have a 
 	 value of 0, unless the projection type is one of PLY, DIS, WRP, in which
 	 case it should be set to 3 */
-      ctype = &coords[0].ctype[4];
       Polynomial = !strcmp (ctype, "-PLY") || !strcmp (ctype, "-DIS") || !strcmp (ctype, "-WRP");
       Polyterm = gfits_scan (header, "NPLYTERM", "%d", 1, &itmp);
@@ -723,4 +753,7 @@
       coords[0].pc2_1 =  sin(rotate*RAD_DEG) / Lambda;
       coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+
+      // read the ZPN coeffients PV2_i (i = 0 < 14)
+      if (!strcmp (&coords[0].ctype[4], "-ZPN")) GetRadialZPN (coords, header);
       break;
 
@@ -744,28 +777,6 @@
       coords[0].pc2_2 /= scale;
 
-      if (!strcmp (&coords[0].ctype[4], "-ZPN")) {
-	int found;
-	for (i = 0; i < 14; i++) {
-	  char name[64];
-	  snprintf (name, 64, "PV2_%d", i);
-	  if (i < 7) {
-	    found = gfits_scan (header, name, "%f", 1, &coords[0].polyterms[0][i]);
-	  } else {
-	    found = gfits_scan (header, name, "%f", 1, &coords[0].polyterms[1][i-7]);
-	  }
-	  if ((i == 0) && !found) {
-	    coords[0].polyterms[0][0] = 0.0;
-	    continue;
-	  }
-	  if ((i == 1) && !found) {
-	    coords[0].polyterms[0][1] = 1.0;
-	    continue;
-	  }
-	  if (!found) {
-	    coords[0].Npolyterms = i;
-	    break;
-	  }
-	}
-      }
+      // read the ZPN coeffients PV2_i (i = 0 < 14)
+      if (!strcmp (&coords[0].ctype[4], "-ZPN")) GetRadialZPN (coords, header);
       break;
 
@@ -819,4 +830,37 @@
   }
   return (status);
+}
+
+int GetRadialZPN (Coords *coords, Header *header) {
+
+  // RA---ZPN can have up to 14 radial polynomial terms.  these are stored in
+  // polyterms[0][0] - [6][0] for the first 7 and [0][1] - [6][1] for the rest
+  // these terms are coeffients of a polynomial of the radial distances
+
+  // read the ZPN coeffients PV2_i (i = 0 < 14)
+  int found;
+  int Nmax = 0;
+  for (int i = 0; i < 14; i++) {
+    char name[64];
+    snprintf (name, 64, "PV2_%d", i);
+    if (i < 7) {
+      coords[0].polyterms[i][0] = 0.0;
+      found = gfits_scan (header, name, "%f", 1, &coords[0].polyterms[i][0]);
+    } else {
+      coords[0].polyterms[i-7][1] = 0.0;
+      found = gfits_scan (header, name, "%f", 1, &coords[0].polyterms[i-7][1]);
+    }
+    // PV2_1 is implicit if not present
+    if ((i == 1) && !found) {
+      coords[0].polyterms[1][0] = 1.0;
+      continue;
+    }
+    // set Npolyterms based on the largest coefficient found
+    if (found) {
+      Nmax = i;
+    }
+  }
+  coords[0].Npolyterms = Nmax + 1;
+  return TRUE;
 }
 
Index: trunk/Ohana/src/libdvo/src/dbExtractMeasures.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 39693)
+++ trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 39926)
@@ -427,8 +427,8 @@
       break;
     case MEAS_TMEAN: /* OK */
+      value.Flt = TimeValue (average[0].Tmean, TimeReference, TimeFormat);
+      break;
+    case MEAS_TRANGE: /* OK */
       value.Flt = GetTimeRange (average[0].Trange, TimeFormat);
-      break;
-    case MEAS_TRANGE: /* OK */
-      value.Flt = TimeValue (average[0].Trange, 0, TimeFormat);
       break;
     case MEAS_NMEAS: /* OK */
@@ -461,12 +461,15 @@
       break;
     case MEAS_RA_FIT_OFFSET: /* OK */
+      // RA_epoch_fit = RA_mean + uR*(t - Tmean)/cos(dec) + plx*parR 
+      // note that this extraction ignores parallax
       dT = (measure[0].t - average[0].Tmean) / (86400*365.25);
-      dR = dvoOffsetR (measure, average);
-      value.Flt = average[0].uR * dT + dR;
+      dR = dvoOffsetR (measure, average); // RA_epoch - RA_mean (** NOT local linear distance **)
+      value.Flt = dR*cos(RAD_DEG*measure[0].D) - average[0].uR * dT;
+      // this is the local linear distance of the measurement from the fit 
       break;
     case MEAS_DEC_FIT_OFFSET: /* OK */
       dT = (measure[0].t - average[0].Tmean) / (86400*365.25);
       dD = dvoOffsetD (measure, average);
-      value.Flt = average[0].uD * dT + dD;
+      value.Flt = dD - average[0].uD * dT;
       break;
     case MEAS_RA_OFFSET_ERR: /* OK */
Index: trunk/Ohana/src/libdvo/src/galaxy_model.c
===================================================================
--- trunk/Ohana/src/libdvo/src/galaxy_model.c	(revision 39693)
+++ trunk/Ohana/src/libdvo/src/galaxy_model.c	(revision 39926)
@@ -28,4 +28,22 @@
     V_sol  =  11.18; // km/sec
     W_sol  =   7.61; // km/sec
+    return TRUE;
+  }
+  if (!strcmp(version, "TEST-CONSTANT")) {
+    // use for testing
+    A_oort = +47.40; // km/sec/kpc
+    B_oort = -47.40; // km/sec/kpc
+    U_sol  =   0.00; // km/sec
+    V_sol  =   0.00; // km/sec
+    W_sol  =   0.00; // km/sec
+    return TRUE;
+  }
+  if (!strcmp(version, "TEST-ZERO")) {
+    // use for testing
+    A_oort =   0.00; // km/sec/kpc
+    B_oort =   0.00; // km/sec/kpc
+    U_sol  =   0.00; // km/sec
+    V_sol  =   0.00; // km/sec
+    W_sol  =   0.00; // km/sec
     return TRUE;
   }
Index: trunk/Ohana/src/libdvo/test/coords.sh
===================================================================
--- trunk/Ohana/src/libdvo/test/coords.sh	(revision 39926)
+++ trunk/Ohana/src/libdvo/test/coords.sh	(revision 39926)
@@ -0,0 +1,62 @@
+
+macro fakeimage-tan
+
+  mcreate test 1000 1000
+
+  keyword test CTYPE1  -w  RA---TAN               ; keyword test CTYPE1  -wc "Algorithm type for axis 1"
+  keyword test CTYPE2  -w  DEC--TAN               ; keyword test CTYPE2  -wc "Algorithm type for axis 2"
+  keyword test CRPIX1  -wf     2997.03245628555   ; keyword test CRPIX1  -wc "Dither offset Y"
+  keyword test CRPIX2  -wf    -944.140242055343   ; keyword test CRPIX2  -wc "Dither offset Y"
+  keyword test CRVAL1  -wf     207.605373039722   ; keyword test CRVAL1  -wc "[deg] Right ascension at the reference pixel"
+  keyword test CRVAL2  -wf    0.113109076969833   ; keyword test CRVAL2  -wc "[deg] Declination at the reference pixel"
+  keyword test CRUNIT1 -w  deg                    ; keyword test CRUNIT1 -wc "Unit of right ascension co-ordinates"
+  keyword test CRUNIT2 -w  deg                    ; keyword test CRUNIT2 -wc "Unit of declination co-ordinates"
+  keyword test CD1_1   -wf -3.34355087531346E-07  ; keyword test CD1_1   -wc "Transformation matrix element"
+  keyword test CD1_2   -wf -0.000111484161257407  ; keyword test CD1_2   -wc "Transformation matrix element"
+  keyword test CD2_1   -wf  0.000111383424202905  ; keyword test CD2_1   -wc "Transformation matrix element"
+  keyword test CD2_2   -wf -3.65044007533155E-07  ; keyword test CD2_2   -wc "Transformation matrix element"
+  # keyword test PV2_1   -wf         1.000000E+00   ; keyword test -c Pol.coeff. for pixel -> celestial coord       
+  # keyword test PV2_2   -wf         0.000000E+00   ; keyword test -c Pol.coeff. for pixel -> celestial coord       
+  # keyword test PV2_3   -wf                 -50.                                                 
+
+end
+
+macro fakeimage-zpn1
+
+  mcreate test 1000 1000
+
+  keyword test CTYPE1  -w  RA---ZPN               ; keyword test CTYPE1  -wc "Algorithm type for axis 1"
+  keyword test CTYPE2  -w  DEC--ZPN               ; keyword test CTYPE2  -wc "Algorithm type for axis 2"
+  keyword test CRPIX1  -wf     2997.03245628555   ; keyword test CRPIX1  -wc "Dither offset Y"
+  keyword test CRPIX2  -wf    -944.140242055343   ; keyword test CRPIX2  -wc "Dither offset Y"
+  keyword test CRVAL1  -wf     207.605373039722   ; keyword test CRVAL1  -wc "[deg] Right ascension at the reference pixel"
+  keyword test CRVAL2  -wf    0.113109076969833   ; keyword test CRVAL2  -wc "[deg] Declination at the reference pixel"
+  keyword test CRUNIT1 -w  deg                    ; keyword test CRUNIT1 -wc "Unit of right ascension co-ordinates"
+  keyword test CRUNIT2 -w  deg                    ; keyword test CRUNIT2 -wc "Unit of declination co-ordinates"
+  keyword test CD1_1   -wf -3.34355087531346E-07  ; keyword test CD1_1   -wc "Transformation matrix element"
+  keyword test CD1_2   -wf -0.000111484161257407  ; keyword test CD1_2   -wc "Transformation matrix element"
+  keyword test CD2_1   -wf  0.000111383424202905  ; keyword test CD2_1   -wc "Transformation matrix element"
+  keyword test CD2_2   -wf -3.65044007533155E-07  ; keyword test CD2_2   -wc "Transformation matrix element"
+  keyword test PV2_1   -wf         1.000000E+00   ; keyword test PV2_1   -wc "Pol.coeff. for pixel -> celestial coord"
+  keyword test PV2_2   -wf         0.000000E+00   ; keyword test PV2_2   -wc "Pol.coeff. for pixel -> celestial coord"
+  keyword test PV2_3   -wf                 -50. 
+
+end
+
+macro test.coords
+  for ix 50 5000 500
+    for iy 50 5000 500
+      coords test -p $ix $iy
+      coords test -c $RA $DEC
+      if (abs($ix - $Xc) > 0.01) 
+	echo bad
+        break
+      end
+      if (abs($iy - $Yc) > 0.01) 
+	echo bad
+        break
+      end
+    end
+  end
+end
+
Index: trunk/Ohana/src/libfits/header/F_H_field.c
===================================================================
--- trunk/Ohana/src/libfits/header/F_H_field.c	(revision 39693)
+++ trunk/Ohana/src/libfits/header/F_H_field.c	(revision 39926)
@@ -90,4 +90,5 @@
       ptr = buf + 9; // start of following keyword
       if (strncmp (field, ptr, Nfield)) continue;
+      if (ptr[Nfield + 1] != '=') continue; // the strncmp above will match a longer string which matches the subset of field (e.g., FOO will match FOOBAR and FOO).  test for the following '=' sign
       Nfound ++;
       if (Nfound == N) return (ptr);
Index: trunk/Ohana/src/libkapa/Makefile
===================================================================
--- trunk/Ohana/src/libkapa/Makefile	(revision 39693)
+++ trunk/Ohana/src/libkapa/Makefile	(revision 39926)
@@ -34,4 +34,5 @@
 $(SRC)/KapaWindow.$(ARCH).o \
 $(SRC)/KapaColors.$(ARCH).o \
+$(SRC)/KapaStyles.$(ARCH).o \
 $(SRC)/KapaOpen.$(ARCH).o
 
Index: trunk/Ohana/src/libkapa/include/kapa.h
===================================================================
--- trunk/Ohana/src/libkapa/include/kapa.h	(revision 39693)
+++ trunk/Ohana/src/libkapa/include/kapa.h	(revision 39926)
@@ -25,29 +25,45 @@
 typedef struct sockaddr_in KapaSockAddress;
 
-typedef struct {
-  float *data1d;
-  float **data2d;
-  int Nx;
-  int Ny;
-} KiiImage;
-
-typedef struct {
-  float x;
-  float y;
-  float dx;
-  float dy;
-  float angle;
-  int type;
-} KiiOverlayBase;
-
-typedef struct {
-  float x;
-  float y;
-  float dx;
-  float dy;
-  float angle;
-  int type;
-  char *text;
-} KiiOverlay;
+// retain historical numerical definitions:
+typedef enum {
+  KAPA_LINE_INVALID_MIN = -1,
+  KAPA_LINE_SOLID       = 0,
+  KAPA_LINE_DOT         = 1,
+  KAPA_LINE_DASH_SHORT  = 2,
+  KAPA_LINE_DASH_LONG   = 3,
+  KAPA_LINE_DOT_DASH    = 4,
+  KAPA_LINE_INVALID_MAX = 5,
+} KapaLineType;
+
+// retain historical numerical definitions:
+typedef enum {
+  KAPA_PLOT_INVALID_MIN = -1,
+  KAPA_PLOT_CONNECT     =  0,
+  KAPA_PLOT_HISTOGRAM   =  1,
+  KAPA_PLOT_POINTS      =  2,
+  KAPA_PLOT_INVALID_MAX =  3,
+} KapaPlotStyle;
+
+typedef enum {
+  KAPA_POINT_INVALID_MIN         = -1,
+  KAPA_POINT_BOX_SOLID           =  0,
+  KAPA_POINT_BOX_OPEN            =  1,
+  KAPA_POINT_CROSS               =  2, // OR PLUS
+  KAPA_POINT_X                   =  3, 
+  KAPA_POINT_Y                   =  4, 
+  KAPA_POINT_TRIANGLE_SOLID      =  5, 
+  KAPA_POINT_TRIANGLE_OPEN       =  6, 
+  KAPA_POINT_CIRCLE_OPEN         =  7, 
+  KAPA_POINT_PENTAGON            =  8, 
+  KAPA_POINT_HEXAGON             =  9, 
+  KAPA_POINT_CIRCLE_SOLID        = 10, 
+  KAPA_POINT_TRIANGLE_SOLID_DOWN = 11, 
+  KAPA_POINT_TRIANGLE_OPEN_DOWN  = 12, 
+  KAPA_POINT_Y_DOWN              = 13, 
+  KAPA_POINT_INVALID_MAX         = 14,
+  KAPA_POINT_PAIR_CONNECT        = 100, // change to a plot style?
+} KapaPointStyle;
+// note that PAIR_CONNECT was historically 100
+
 
 typedef enum {
@@ -75,4 +91,30 @@
   KAPA_PS_RAWPAGE
 } KapaPSmode;
+
+typedef struct {
+  float *data1d;
+  float **data2d;
+  int Nx;
+  int Ny;
+} KiiImage;
+
+typedef struct {
+  float x;
+  float y;
+  float dx;
+  float dy;
+  float angle;
+  int type;
+} KiiOverlayBase;
+
+typedef struct {
+  float x;
+  float y;
+  float dx;
+  float dy;
+  float angle;
+  int type;
+  char *text;
+} KiiOverlay;
 
 typedef struct {
@@ -219,4 +261,9 @@
 unsigned long *KapaX11colors (Display *display, Colormap colormap, unsigned long default_color, int *Ncolors);
 
+/* KapaStyles.c */
+KapaLineType KapaLineTypeFromString (char *string);
+KapaPlotStyle KapaPlotStyleFromString (char *string);
+KapaPointStyle KapaPointStyleFromString (char *string);
+
 /* RotFont.c */
 void InitRotFonts PROTO((void));
Index: trunk/Ohana/src/libkapa/src/KapaOpen.c
===================================================================
--- trunk/Ohana/src/libkapa/src/KapaOpen.c	(revision 39693)
+++ trunk/Ohana/src/libkapa/src/KapaOpen.c	(revision 39926)
@@ -6,5 +6,5 @@
 # define MY_PORT 2500
 # define MY_PORT_MAX 2520
-# define MY_WAIT 100000
+# define MY_WAIT 1000000
 # define DEBUG 0
 
Index: trunk/Ohana/src/libkapa/src/KapaStyles.c
===================================================================
--- trunk/Ohana/src/libkapa/src/KapaStyles.c	(revision 39926)
+++ trunk/Ohana/src/libkapa/src/KapaStyles.c	(revision 39926)
@@ -0,0 +1,140 @@
+# include <kapa_internal.h>
+
+KapaLineType KapaLineTypeFromString (char *string) {
+
+  char *endptr;
+
+  int iValue = strtol (string, &endptr, 10);
+  if (*endptr == 0) {
+    if ((iValue > KAPA_LINE_INVALID_MIN) && 
+	(iValue < KAPA_LINE_INVALID_MAX)) {
+      return iValue;
+    }
+    // silently return a valid value?
+    return KAPA_LINE_SOLID;
+  }
+
+  if (!strcasecmp (string,  "solid"))     return KAPA_LINE_SOLID;
+  if (!strcasecmp (string,  "dot"))       return KAPA_LINE_DOT;
+  if (!strcasecmp (string,  "longdash"))  return KAPA_LINE_DASH_LONG;
+  if (!strcasecmp (string,  "shortdash")) return KAPA_LINE_DASH_SHORT;
+  if (!strcasecmp (string,  "dotdash"))   return KAPA_LINE_DOT_DASH;
+
+  if (!strcasecmp (string,  "dash"))      return KAPA_LINE_DASH_LONG;
+  if (!strcasecmp (string,  "dashdot"))   return KAPA_LINE_DOT_DASH;
+
+  return KAPA_LINE_SOLID;
+}
+
+KapaPlotStyle KapaPlotStyleFromString (char *string) {
+
+  char *endptr;
+
+  int iValue = strtol (string, &endptr, 10);
+  if (*endptr == 0) {
+    if ((iValue > KAPA_PLOT_INVALID_MIN) && 
+	(iValue < KAPA_PLOT_INVALID_MAX)) {
+      return iValue;
+    }
+    // silently return a valid value?
+    return KAPA_PLOT_POINTS;
+  }
+
+  if (!strcasecmp (string,  "points"))    return KAPA_PLOT_POINTS;
+  if (!strcasecmp (string,  "pts"))       return KAPA_PLOT_POINTS;
+  if (!strcasecmp (string,  "connect"))   return KAPA_PLOT_CONNECT;
+  if (!strcasecmp (string,  "line"))      return KAPA_PLOT_CONNECT;
+  if (!strcasecmp (string,  "histogram")) return KAPA_PLOT_HISTOGRAM;
+
+  if (strlen(string) > 2) {
+    if (!strncasecmp (string, "histogram", strlen(string))) return KAPA_PLOT_HISTOGRAM;
+    if (!strncasecmp (string, "connect",   strlen(string))) return KAPA_PLOT_CONNECT;
+    if (!strncasecmp (string, "points",    strlen(string))) return KAPA_PLOT_POINTS;
+  }
+  // silently return a valid value?
+  return KAPA_PLOT_POINTS;
+}
+
+KapaPointStyle KapaPointStyleFromString (char *string) {
+
+  char *endptr;
+
+  int iValue = strtol (string, &endptr, 10);
+  if (*endptr == 0) {
+    // note that PAIR_CONNECT was historically 100 [outside MIN - MAX]
+    if (iValue == KAPA_POINT_PAIR_CONNECT) return iValue;
+    if ((iValue > KAPA_POINT_INVALID_MIN) && 
+	(iValue < KAPA_POINT_INVALID_MAX)) {
+      return iValue;
+    }
+    // silently return a valid value?
+    return KAPA_POINT_BOX_SOLID;
+  }
+
+  if (!strcasecmp (string,  "box"))              return KAPA_POINT_BOX_SOLID;
+  if (!strcasecmp (string,  "circle"))           return KAPA_POINT_CIRCLE_SOLID        ;
+  if (!strcasecmp (string,  "cross"))            return KAPA_POINT_CROSS               ;
+  if (!strcasecmp (string,  "fbox"))             return KAPA_POINT_BOX_SOLID;
+  if (!strcasecmp (string,  "fcircle"))          return KAPA_POINT_CIRCLE_SOLID        ;
+  if (!strcasecmp (string,  "fhexagon"))         return KAPA_POINT_HEXAGON             ;
+  if (!strcasecmp (string,  "fpentagon"))        return KAPA_POINT_PENTAGON            ;
+  if (!strcasecmp (string,  "ftriangle"))        return KAPA_POINT_TRIANGLE_SOLID      ;
+  if (!strcasecmp (string,  "ftriangledown"))    return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+  if (!strcasecmp (string,  "ftridown"))         return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+  if (!strcasecmp (string,  "hexagon"))          return KAPA_POINT_HEXAGON             ;
+  if (!strcasecmp (string,  "obox"))             return KAPA_POINT_BOX_OPEN;
+  if (!strcasecmp (string,  "ocircle"))          return KAPA_POINT_CIRCLE_OPEN         ;
+  if (!strcasecmp (string,  "openbox"))          return KAPA_POINT_BOX_OPEN            ;
+  if (!strcasecmp (string,  "opencircle"))       return KAPA_POINT_CIRCLE_OPEN         ;
+  if (!strcasecmp (string,  "opentriangle"))     return KAPA_POINT_TRIANGLE_OPEN       ;
+  if (!strcasecmp (string,  "opentriangledown")) return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+  if (!strcasecmp (string,  "otriangle"))        return KAPA_POINT_TRIANGLE_OPEN       ;
+  if (!strcasecmp (string,  "otriangledown"))    return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+  if (!strcasecmp (string,  "otridown"))         return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+  if (!strcasecmp (string,  "pairs"))            return KAPA_POINT_PAIR_CONNECT;
+  if (!strcasecmp (string,  "pentagon"))         return KAPA_POINT_PENTAGON            ;
+  if (!strcasecmp (string,  "plus"))             return KAPA_POINT_CROSS               ;
+  if (!strcasecmp (string,  "solidtriangle"))    return KAPA_POINT_TRIANGLE_SOLID      ;
+  if (!strcasecmp (string,  "triangle"))         return KAPA_POINT_TRIANGLE_SOLID      ;
+  if (!strcasecmp (string,  "triangledown"))     return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+  if (!strcasecmp (string,  "tridown"))          return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+  if (!strcasecmp (string,  "x"))                return KAPA_POINT_X                   ;
+  if (!strcasecmp (string,  "y"))                return KAPA_POINT_Y                   ;
+  if (!strcasecmp (string,  "ydown"))            return KAPA_POINT_Y_DOWN              ;
+
+  int Nchar = strlen(string);
+  if (Nchar > 2) {
+    if (!strncasecmp (string,  "box", Nchar))              return KAPA_POINT_BOX_SOLID           ;
+    if (!strncasecmp (string,  "circle", Nchar))           return KAPA_POINT_CIRCLE_SOLID        ;
+    if (!strncasecmp (string,  "cross", Nchar))            return KAPA_POINT_CROSS               ;
+    if (!strncasecmp (string,  "fbox", Nchar))             return KAPA_POINT_BOX_SOLID;
+    if (!strncasecmp (string,  "fcircle", Nchar))          return KAPA_POINT_CIRCLE_SOLID        ;
+    if (!strncasecmp (string,  "fhexagon", Nchar))         return KAPA_POINT_HEXAGON             ;
+    if (!strncasecmp (string,  "fpentagon", Nchar))        return KAPA_POINT_PENTAGON            ;
+    if (!strncasecmp (string,  "ftriangle", Nchar))        return KAPA_POINT_TRIANGLE_SOLID      ;
+    if (!strncasecmp (string,  "ftriangledown", Nchar))    return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+    if (!strncasecmp (string,  "ftridown", Nchar))         return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+    if (!strncasecmp (string,  "hexagon", Nchar))          return KAPA_POINT_HEXAGON             ;
+    if (!strncasecmp (string,  "obox", Nchar))             return KAPA_POINT_BOX_OPEN;
+    if (!strncasecmp (string,  "ocircle", Nchar))          return KAPA_POINT_CIRCLE_OPEN         ;
+    if (!strncasecmp (string,  "openbox", Nchar))          return KAPA_POINT_BOX_OPEN            ;
+    if (!strncasecmp (string,  "opencircle", Nchar))       return KAPA_POINT_CIRCLE_OPEN         ;
+    if (!strncasecmp (string,  "opentriangle", Nchar))     return KAPA_POINT_TRIANGLE_OPEN       ;
+    if (!strncasecmp (string,  "opentriangledown", Nchar)) return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+    if (!strncasecmp (string,  "opentridown", Nchar))      return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+    if (!strncasecmp (string,  "otriangle", Nchar))        return KAPA_POINT_TRIANGLE_OPEN       ;
+    if (!strncasecmp (string,  "otriangledown", Nchar))    return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+    if (!strncasecmp (string,  "otridown", Nchar))         return KAPA_POINT_TRIANGLE_OPEN_DOWN  ;
+    if (!strncasecmp (string,  "pairs", Nchar))            return KAPA_POINT_PAIR_CONNECT;
+    if (!strncasecmp (string,  "pentagon", Nchar))         return KAPA_POINT_PENTAGON            ;
+    if (!strncasecmp (string,  "plus", Nchar))             return KAPA_POINT_CROSS               ;
+    if (!strncasecmp (string,  "solidtriangle", Nchar))    return KAPA_POINT_TRIANGLE_SOLID      ;
+    if (!strncasecmp (string,  "triangle", Nchar))         return KAPA_POINT_TRIANGLE_SOLID      ;
+    if (!strncasecmp (string,  "triangledown", Nchar))     return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+    if (!strncasecmp (string,  "tridown", Nchar))          return KAPA_POINT_TRIANGLE_SOLID_DOWN ;
+    if (!strncasecmp (string,  "ydown", Nchar))            return KAPA_POINT_Y_DOWN              ;
+  }
+
+  return KAPA_POINT_BOX_SOLID;
+}
+
Index: trunk/Ohana/src/libkapa/src/KapaWindow.c
===================================================================
--- trunk/Ohana/src/libkapa/src/KapaWindow.c	(revision 39693)
+++ trunk/Ohana/src/libkapa/src/KapaWindow.c	(revision 39926)
@@ -449,2 +449,3 @@
   return (TRUE);
 }
+
Index: trunk/Ohana/src/libkapa/src/bDrawFuncs.c
===================================================================
--- trunk/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 39693)
+++ trunk/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 39926)
@@ -222,6 +222,16 @@
   e = 0;
   for (X = X1, N = 0; X <= X2; X++, N++) {
-    if (buffer->bType == 1) { DashOn = (N % 10) < 5; }
-    if (buffer->bType == 2) { DashOn = (N % 6) < 3; }
+    if (buffer->bType == KAPA_LINE_DOT) {
+      DashOn = (N % 5) == 0 || (N % 5) == 1;
+    }
+    if (buffer->bType == KAPA_LINE_DASH_SHORT) {
+      DashOn = (N % 8) < 4;
+    }
+    if (buffer->bType == KAPA_LINE_DASH_LONG) {
+      DashOn = (N % 16) < 8;
+    }
+    if (buffer->bType == KAPA_LINE_DOT_DASH) {
+      DashOn = ((N % 12) < 2) || ((N % 12 >= 6) && (N % 12 < 10)) ;
+    }
     if (swapcoords) {
       if (DashOn) bDrawPoint (buffer, Y,X);
Index: trunk/Ohana/src/opihi/cmd.astro/csystem.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/csystem.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.astro/csystem.c	(revision 39926)
@@ -125,6 +125,6 @@
   opihi_flt *yptr = yvec[0].elements.Flt;
 
-  opihi_flt *uxptr = uxvec ? xvec[0].elements.Flt : NULL;
-  opihi_flt *uyptr = uyvec ? yvec[0].elements.Flt : NULL;
+  opihi_flt *uxptr = uxvec ? uxvec[0].elements.Flt : NULL;
+  opihi_flt *uyptr = uyvec ? uyvec[0].elements.Flt : NULL;
 
   for (i = 0; i < xvec[0].Nelements; i++, xptr++, yptr++) {
Index: trunk/Ohana/src/opihi/cmd.astro/fitplx_irls.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/fitplx_irls.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.astro/fitplx_irls.c	(revision 39926)
@@ -158,6 +158,6 @@
     // now that the mask has been updated, we need to recalculate mean epoch and positions
     // XXX make this conditional on actually masking unmasked points above
-    PlxSetMeanEpoch (R, D, T, &Rmean, &Dmean, &Tmean, mask, Ntotal);
-    PlxSetEpochPosition (&fitdata, R, D, dR, dD, T, mask, Ntotal, &coords, Tmean);
+    // PlxSetMeanEpoch (R, D, T, &Rmean, &Dmean, &Tmean, mask, Ntotal);
+    // PlxSetEpochPosition (&fitdata, R, D, dR, dD, T, mask, Ntotal, &coords, Tmean);
 
     PlxFitData sample;
@@ -218,13 +218,37 @@
   // fprintf (stderr, "%f +/- %f | %f %f\n", fit.p, fit.dp, fit.uR, fit.uD);
 
-/*
-  FILE *f = fopen ("test.pf.dat", "w");
+  Vector *dRresPMP, *dDresPMP, *dRresPLX, *dDresPLX;
+
+  // save fit residuals (with only pm removed, and pm and plx removed)
+  if ((dRresPMP = SelectVector ("dRresPMP", ANYVECTOR, TRUE)) == NULL) ESCAPE ("cannot generate vector %s\n", "dRresPMP");
+  if ((dDresPMP = SelectVector ("dDresPMP", ANYVECTOR, TRUE)) == NULL) ESCAPE ("cannot generate vector %s\n", "dDresPMP");
+  if ((dRresPLX = SelectVector ("dRresPLX", ANYVECTOR, TRUE)) == NULL) ESCAPE ("cannot generate vector %s\n", "dRresPLX");
+  if ((dDresPLX = SelectVector ("dDresPLX", ANYVECTOR, TRUE)) == NULL) ESCAPE ("cannot generate vector %s\n", "dDresPLX");
+    
+  ResetVector (dRresPMP, OPIHI_FLT, Ntotal);
+  ResetVector (dDresPMP, OPIHI_FLT, Ntotal);
+  ResetVector (dRresPLX, OPIHI_FLT, Ntotal);
+  ResetVector (dDresPLX, OPIHI_FLT, Ntotal);
+  
   for (i = 0; i < Ntotal; i++) {
-    double Xf = fit.Ro + fit.uR*fitdata.t[i] + fit.p*fitdata.pX[i];
-    double Yf = fit.Do + fit.uD*fitdata.t[i] + fit.p*fitdata.pY[i];
-    fprintf (f, "%f : %f %f : %f %f : %f : %f %f : %f %f\n", T[i], R[i], D[i], Xf, Yf, fitdata.t[i], fitdata.X[i], fitdata.Y[i], fitdata.pX[i], fitdata.pY[i]);
-  }
-  fclose (f);
-*/
+    
+    double x0, y0;
+    RD_to_XY (&x0, &y0, R[i], D[i], &coords);
+
+    double pX0, pY0;
+    ParFactor (&pX0, &pY0, R[i], D[i], T[i]);
+
+    double t0 = (T[i] - Tmean)/365.25;
+
+    double Xpmp = fit.Ro + fit.uR*t0 + fit.p*pX0;
+    double Ypmp = fit.Do + fit.uD*t0 + fit.p*pY0;
+    double Xplx = fit.Ro + fit.uR*t0;
+    double Yplx = fit.Do + fit.uD*t0;
+
+    dRresPMP->elements.Flt[i] = x0 - Xpmp;
+    dDresPMP->elements.Flt[i] = y0 - Ypmp;
+    dRresPLX->elements.Flt[i] = x0 - Xplx;
+    dDresPLX->elements.Flt[i] = y0 - Yplx;
+  }
 
   // fprintf (stderr, "Roff, Doff: %f, %f; dRo, dDo: %f, %f\n", fit.Ro, fit.Do, fit.dRo, fit.dDo);
Index: trunk/Ohana/src/opihi/cmd.astro/spex1dgas.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/spex1dgas.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.astro/spex1dgas.c	(revision 39926)
@@ -108,12 +108,7 @@
   IDList = NULL;
   XoList = NULL;
-  { 
-    // init random numbers
-    long A, B;
-    A = time(NULL);
-    for (B = 0; A == time(NULL); B++);
-    srand48(B);
-  }
  
+  // srand48() is called by startup.c
+
   if (argc != 11) goto usage;
 
Index: trunk/Ohana/src/opihi/cmd.astro/spex2dgas.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/spex2dgas.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.astro/spex2dgas.c	(revision 39926)
@@ -120,12 +120,6 @@
   float XoMax, YoMax;
 
-  { 
-    // init random numbers
-    long A, B;
-    A = time(NULL);
-    for (B = 0; A == time(NULL); B++);
-    srand48(B);
-  }
- 
+  // srand48() is called by startup.c
+
   if (argc != 9) goto usage;
 
Index: trunk/Ohana/src/opihi/cmd.astro/spexseq.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/spexseq.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.astro/spexseq.c	(revision 39926)
@@ -90,13 +90,7 @@
   int Nobject = 0;
 
-  { 
-    // init random numbers
-    long A, B;
-    A = time(NULL);
-    for (B = 0; A == time(NULL); B++);
-    srand48(B);
-  }
- 
   if (argc != 6) goto usage;
+
+  // srand48() is called by startup.c
 
   // XXX enforce matching lengths on the three vectors
Index: trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 39926)
@@ -124,4 +124,5 @@
 $(SRC)/resize.$(ARCH).o		\
 $(SRC)/relocate.$(ARCH).o	\
+$(SRC)/rndseed.$(ARCH).o		\
 $(SRC)/roll.$(ARCH).o		\
 $(SRC)/rotate.$(ARCH).o	\
Index: trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/init.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.data/init.c	(revision 39926)
@@ -113,4 +113,5 @@
 int reindex          PROTO((int, char **));
 int relocate         PROTO((int, char **));
+int rndseed          PROTO((int, char **));
 int roll             PROTO((int, char **));
 int rotate           PROTO((int, char **));
@@ -293,4 +294,5 @@
   {1, "relocate",     relocate,         "set graphics/image window position"},
   {1, "roll",         roll,             "roll image to new start point"},
+  {1, "rndseed",      rndseed,          "set the pseudo-random seed"},
   {1, "rotate",       rotate,           "rotate image"},
   {1, "save",         save,             "save an SAOimage style image overlay"},
Index: trunk/Ohana/src/opihi/cmd.data/match2d.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/match2d.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.data/match2d.c	(revision 39926)
@@ -1,6 +1,9 @@
 # include "data.h"
 
-int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2);
+int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2, Vector *radiusMatch);
 int find_matches2d_closest (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index);
+
+int find_matches2d_sphere (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2, Vector *radiusMatch);
+int find_matches2d_sphere_closest (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index);
 
 // match2d (X1) (Y1) (X2) (Y2) (Radius) [-index1 (index1)] [-index2 (index2)] [-nomatch1 nomatch1] [-nomatch2 nomatch2]
@@ -23,4 +26,14 @@
   }
 
+  int SPHERE_DISTANCE = FALSE;
+  if ((N = get_argument (argc, argv, "-sphere"))) {
+    remove_argument (N, &argc, argv);
+    SPHERE_DISTANCE = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-sky"))) {
+    remove_argument (N, &argc, argv);
+    SPHERE_DISTANCE = TRUE;
+  }
+
   if ((N = get_argument (argc, argv, "-index1"))) {
     remove_argument (N, &argc, argv);
@@ -37,4 +50,16 @@
   } else {
     if ((index2 = SelectVector ("index2", ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+  }
+
+  
+  Vector *radiusMatch = NULL;
+  if ((N = get_argument (argc, argv, "-radius"))) {
+    if (CLOSEST) {
+      gprint (GP_ERR, "error: -radius and -closest are currently incompatible\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if ((radiusMatch = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
   }
 
@@ -84,11 +109,19 @@
   }
 
-  if (CLOSEST) {
+  if (SPHERE_DISTANCE) {
+    if (CLOSEST) {
+      find_matches2d_sphere_closest (X1vec, Y1vec, X2vec, Y2vec, Radius, index1);
+      find_matches2d_sphere_closest (X2vec, Y2vec, X1vec, Y1vec, Radius, index2);
+    } else {
+      find_matches2d_sphere (X1vec, Y1vec, X2vec, Y2vec, Radius, index1, index2, radiusMatch);
+    }
+  } else {
+    if (CLOSEST) {
       find_matches2d_closest (X1vec, Y1vec, X2vec, Y2vec, Radius, index1);
       find_matches2d_closest (X2vec, Y2vec, X1vec, Y1vec, Radius, index2);
-  } else {
-      find_matches2d (X1vec, Y1vec, X2vec, Y2vec, Radius, index1, index2);
-  }
-
+    } else {
+      find_matches2d (X1vec, Y1vec, X2vec, Y2vec, Radius, index1, index2, radiusMatch);
+    }
+  }
   return (TRUE);
 
@@ -108,9 +141,13 @@
   gprint (GP_ERR, "use 'reindex' to generate new vectors based on these index vectors\n");
 
+  gprint (GP_ERR, "if -sphere or -sky is supplied, (x1,y1) and (x2,y2) are treaded as (ra,dec) or (long,lat) pairs in degrees\n");
+
+  gprint (GP_ERR, "if -radius (vector) is supplied, the vector will be filled with the distance between the matched pairs\n");
+  gprint (GP_ERR, "  not valid with -closest\n");
   return FALSE;
 }
 
 // we are not defining a relative offset DX,DY for now
-int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2) {
+int find_matches2d (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2, Vector *radiusMatch) {
   
   off_t i, j, first_j, I, J, *N1, *N2, Nmatch, NMATCH, DMATCH;
@@ -122,4 +159,5 @@
   ResetVector (index1, OPIHI_INT, NMATCH);
   ResetVector (index2, OPIHI_INT, NMATCH);
+  if (radiusMatch) ResetVector (radiusMatch, OPIHI_FLT, NMATCH);
 
   ALLOCATE (N1, off_t, X1->Nelements);
@@ -154,4 +192,5 @@
 	index1->elements.Int[Nmatch] = I;
 	index2->elements.Int[Nmatch] = J;
+	if (radiusMatch) radiusMatch->elements.Flt[Nmatch] = dR;
 
 	// XXX track matches 1 and 2 with internal vector, save new nomatch index vectors
@@ -163,4 +202,5 @@
 	  REALLOCATE (index1->elements.Int, opihi_int, NMATCH);
 	  REALLOCATE (index2->elements.Int, opihi_int, NMATCH);
+	  if (radiusMatch) { REALLOCATE (radiusMatch->elements.Flt, opihi_flt, NMATCH); }
 	}
       }
@@ -171,4 +211,5 @@
   index1->Nelements = Nmatch;
   index2->Nelements = Nmatch;
+  if (radiusMatch) radiusMatch->Nelements = Nmatch;
 
   free (N1);
@@ -246,2 +287,231 @@
   return (TRUE);
 }
+
+double gcdist (double r1, double d1, double r2, double d2) {
+  double num,den;
+  r1 *= RAD_DEG;
+  d1 *= RAD_DEG;
+  r2 *= RAD_DEG;
+  d2 *= RAD_DEG;
+
+  num = sqrt(pow((cos(d2) * sin(r2 - r1)),2) +
+	     pow((cos(d1) * sin(d2) -
+		  sin(d1) * cos(d2) * cos(r2 - r1)),2));
+  den = (sin(d1) * sin(d2) + cos(d1) * cos(d2) * cos(r2 - r1));
+  return(atan2(num,den) * (180 / M_PI));
+}
+
+typedef struct {
+  double sD;
+  double cD;
+  double sR;
+  double cR;
+} Match2D_PreCalc;
+
+double gcdist_PreCalc_v0 (Match2D_PreCalc *p1, Match2D_PreCalc *p2) {
+  double num,den;
+
+  num = sqrt(pow((p2->cD * (p2->sR*p1->cR - p1->sR*p2->cR)),2) +
+	     pow((p1->cD * p2->sD -
+		  p1->sD * p2->cD * (p2->cR*p1->cR + p2->sR*p1->sR)),2));
+  den = (p1->sD * p2->sD + p1->cD * p2->cD * (p2->cR*p1->cR + p2->sR*p1->sR));
+  return(atan2(num,den) * (180 / M_PI));
+}
+
+// we are not defining a relative offset DX,DY for now
+double gcdist_PreCalc (Match2D_PreCalc *p1, Match2D_PreCalc *p2) {
+  double num,den;
+
+  // double Qd = p1->sD * p1->cD * p2->sD * p2->cD;
+  // double Qr = p1->sR * p1->cR * p2->sR * p2->cR;
+
+  //  double Xa 
+  //    = SQ(p2->cD * p1->cR * p2->sR) 
+  //    + SQ(p2->cD * p1->sR * p2->cR) -
+  //    - 2 * SQ(p2->cD) * Qr;
+
+  double cdR = (p2->cR*p1->cR + p2->sR*p1->sR);
+
+  double Xa = SQ(p2->cD * p2->sR * p1->cR - p2->cD * p1->sR * p2->cR);
+  double Xb = SQ(p1->cD * p2->sD - p1->sD * p2->cD * cdR);
+
+  num = sqrt(Xa + Xb);
+  den = (p1->sD * p2->sD + p1->cD * p2->cD * cdR);
+  return(atan2(num,den) * (180 / M_PI));
+}
+
+// we are not defining a relative offset DX,DY for now
+int find_matches2d_sphere (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index1, Vector *index2, Vector *radiusMatch) {
+  
+  off_t i, j, first_j, I, J, *N1, *N2, Nmatch, NMATCH, DMATCH;
+  double dY, dR;
+
+  NMATCH = MAX(MAX(0.05*X1->Nelements, 0.05*X2->Nelements), 1000);
+  DMATCH = NMATCH;
+
+  ResetVector (index1, OPIHI_INT, NMATCH);
+  ResetVector (index2, OPIHI_INT, NMATCH);
+  if (radiusMatch) ResetVector (radiusMatch, OPIHI_FLT, NMATCH);
+
+  ALLOCATE (N1, off_t, X1->Nelements);
+  ALLOCATE (N2, off_t, X2->Nelements);
+
+  ALLOCATE_PTR (A1, Match2D_PreCalc, X1->Nelements);
+  ALLOCATE_PTR (A2, Match2D_PreCalc, X2->Nelements);
+
+  for (i = 0; i < X1->Nelements; i++) { 
+    A1[i].sR = sin(RAD_DEG*X1->elements.Flt[i]);
+    A1[i].cR = cos(RAD_DEG*X1->elements.Flt[i]);
+    A1[i].sD = sin(RAD_DEG*Y1->elements.Flt[i]);
+    A1[i].cD = cos(RAD_DEG*Y1->elements.Flt[i]);
+    N1[i] = i; 
+  }
+  for (i = 0; i < X2->Nelements; i++) { 
+    A2[i].sR = sin(RAD_DEG*X2->elements.Flt[i]);
+    A2[i].cR = cos(RAD_DEG*X2->elements.Flt[i]);
+    A2[i].sD = sin(RAD_DEG*Y2->elements.Flt[i]);
+    A2[i].cD = cos(RAD_DEG*Y2->elements.Flt[i]);
+    N2[i] = i; 
+  }
+
+  // sort from one pole to the other
+  sort_coords_indexonly (Y1->elements.Flt, X1->elements.Flt, N1, X1->Nelements);
+  sort_coords_indexonly (Y2->elements.Flt, X2->elements.Flt, N2, X2->Nelements);
+
+  Nmatch = 0;
+  for (i = j = 0; (i < X1->Nelements) && (j < X2->Nelements);) {
+    I = N1[i];
+    J = N2[j];
+
+    // we can use dY as minimal requirement: if dY > Radius, we are too far apart
+    dY = Y1->elements.Flt[I] - Y2->elements.Flt[J];
+
+    if (dY <= -1.02*Radius) { i++; continue; }
+    if (dY >= +1.02*Radius) { j++; continue; }
+
+    // look for all matches of list2() to list1(i)
+    first_j = j;
+    for (j = first_j; (dY > -1.02*Radius) && (j < X2->Nelements); j++) {
+      J = N2[j];
+
+      dR = gcdist_PreCalc (&A1[I], &A2[J]);
+      // dR = gcdist (X1->elements.Flt[I], Y1->elements.Flt[I], X2->elements.Flt[J], Y2->elements.Flt[J]);
+
+      if (dR < Radius) {
+	index1->elements.Int[Nmatch] = I;
+	index2->elements.Int[Nmatch] = J;
+	if (radiusMatch) radiusMatch->elements.Flt[Nmatch] = dR;
+
+	// XXX track matches 1 and 2 with internal vector, save new nomatch index vectors
+	// after this loop
+
+	Nmatch ++;
+	if (Nmatch >= NMATCH) {
+	  NMATCH += DMATCH;
+	  REALLOCATE (index1->elements.Int, opihi_int, NMATCH);
+	  REALLOCATE (index2->elements.Int, opihi_int, NMATCH);
+	  if (radiusMatch) { REALLOCATE (radiusMatch->elements.Flt, opihi_flt, NMATCH); }
+	}
+      }
+    }
+    j = first_j;
+    i++;
+  }
+  index1->Nelements = Nmatch;
+  index2->Nelements = Nmatch;
+  if (radiusMatch) radiusMatch->Nelements = Nmatch;
+
+  free (A1);
+  free (A2);
+
+  free (N1);
+  free (N2);
+
+  return (TRUE);
+}
+
+// we are not defining a relative offset DX,DY for now
+int find_matches2d_sphere_closest (Vector *X1, Vector *Y1, Vector *X2, Vector *Y2, double Radius, Vector *index) {
+  
+  off_t i, j, Jmin, Ji, I, J, *N1, *N2;
+  double dY, dR, Rmin;
+
+  ResetVector (index, OPIHI_INT, X1->Nelements);
+  for (i = 0; i < index->Nelements; i++) { index->elements.Int[i] = -1; }
+
+  ALLOCATE (N1, off_t, X1->Nelements);
+  ALLOCATE (N2, off_t, X2->Nelements);
+
+  ALLOCATE_PTR (A1, Match2D_PreCalc, X1->Nelements);
+  ALLOCATE_PTR (A2, Match2D_PreCalc, X2->Nelements);
+
+  for (i = 0; i < X1->Nelements; i++) { 
+    A1[i].sR = sin(RAD_DEG*X1->elements.Flt[i]);
+    A1[i].cR = cos(RAD_DEG*X1->elements.Flt[i]);
+    A1[i].sD = sin(RAD_DEG*Y1->elements.Flt[i]);
+    A1[i].cD = cos(RAD_DEG*Y1->elements.Flt[i]);
+    N1[i] = i; 
+  }
+  for (i = 0; i < X2->Nelements; i++) { 
+    A2[i].sR = sin(RAD_DEG*X2->elements.Flt[i]);
+    A2[i].cR = cos(RAD_DEG*X2->elements.Flt[i]);
+    A2[i].sD = sin(RAD_DEG*Y2->elements.Flt[i]);
+    A2[i].cD = cos(RAD_DEG*Y2->elements.Flt[i]);
+    N2[i] = i; 
+  }
+
+  // sort from one pole to the other
+  sort_coords_indexonly (Y1->elements.Flt, X1->elements.Flt, N1, X1->Nelements);
+  sort_coords_indexonly (Y2->elements.Flt, X2->elements.Flt, N2, X2->Nelements);
+
+  for (i = j = 0; (i < X1->Nelements) && (j < X2->Nelements);) {
+    I = N1[i];
+    J = N2[j];
+
+    // we can use dY as minimal requirement: if dY > Radius, we are too far apart
+    dY = Y1->elements.Flt[I] - Y2->elements.Flt[J];
+
+    if (dY <= -1.02*Radius) { 
+      // no match in list 2 to this entry
+      index->elements.Int[I] = -1; // (probably not needed --- index is init'ed above)o
+      i++; 
+      continue; 
+    }
+    if (dY >= +1.02*Radius) { j++; continue; }
+
+    // look for all matches of list2() to list1(i)
+    Jmin = -1;
+    Rmin = Radius;
+    for (Ji = j; (dY > -1.02*Radius) && (Ji < X2->Nelements); Ji++) {
+      J = N2[Ji];
+
+      dR = gcdist_PreCalc (&A1[I], &A2[J]);
+      // dR = gcdist (X1->elements.Flt[I], Y1->elements.Flt[I], X2->elements.Flt[J], Y2->elements.Flt[J]);
+
+      if (dR < Rmin) {
+	Rmin = dR;
+	Jmin = J;
+      }
+    }
+    
+
+    // no match in list 2 to this entry
+    if (Jmin == -1) {
+      index->elements.Int[I] = -1;
+      i++;
+      continue;
+    }
+    index->elements.Int[I] = Jmin;
+    i++;
+  }
+
+  free (A1);
+  free (A2);
+
+  free (N1);
+  free (N2);
+
+  return (TRUE);
+}
+
+
Index: trunk/Ohana/src/opihi/cmd.data/rndseed.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/rndseed.c	(revision 39926)
+++ trunk/Ohana/src/opihi/cmd.data/rndseed.c	(revision 39926)
@@ -0,0 +1,18 @@
+# include "data.h"
+
+int rndseed (int argc, char **argv) {
+  
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: rndseed (value)\n");
+    return (FALSE);
+  }
+
+  /* init srand for rnd numbers elsewhere */
+  long A = atol (argv[1]);
+  srand48(A);
+
+  return (TRUE);
+}
+
+ 
+  
Index: trunk/Ohana/src/opihi/cmd.data/stats-new.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/stats-new.c	(revision 39693)
+++ trunk/Ohana/src/opihi/cmd.data/stats-new.c	(revision 39926)
@@ -129,7 +129,5 @@
   ALLOCATE (values, float, Nsample);
     
-  A = time(NULL);
-  for (B = 0; A == time(NULL); B++);
-  srand48(B);
+  // srand48() is called by startup.c
  
   *buffer = (float *) matrix[0].buffer;
Index: trunk/Ohana/src/opihi/cmd.data/test/fit1d_irls.sh
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/test/fit1d_irls.sh	(revision 39926)
+++ trunk/Ohana/src/opihi/cmd.data/test/fit1d_irls.sh	(revision 39926)
@@ -0,0 +1,347 @@
+
+list tests
+ test1
+ test2
+ test3
+ test4
+ test5
+ test6
+ test7
+ test8
+end
+
+## NOTE: this is not a TAP test
+macro mean.test
+  if ($0 != 2)
+    echo "USAGE: mean.test (errorbar)"
+    break
+  end
+
+  create x 0 100
+
+  delete C0fit dC0fit Cnfit Mfit dMfit
+  for i 0 500
+    gaussdev y x[] 0 1.0   ; # mean of 0, sigma of 1
+    
+    set dy = 1.0 + zero(x) ; # set error to be correct
+    fit1d_irls -q x y 0 -dy dy -wt wt -mask mask -use-median -Nboot 1000
+
+    concat $C0    C0fit
+    concat $dC0  dC0fit
+
+    vstat -q y
+    concat $MEAN Mfit
+    concat {$SIGMA / sqrt($NPTS)} dMfit
+  end
+
+  vstat -q C0fit;  set MeanC  = $MEAN; set StdevC = $SIGMA
+  vstat -q dC0fit; set MeanDC = $MEAN
+  vstat -q Mfit;   set MeanM  = $MEAN; set StdevM = $SIGMA
+  vstat -q dMfit;  set MeanDM = $MEAN
+
+  fprintf "%7.3f %7.3f" $MeanC $MeanM
+  fprintf "%7.3f %7.3f" $StdevC $StdevM
+end
+
+macro cliptest.plot
+  if ($0 != 3)
+    echo "USAGE: cliptest.plot (errorbar) (output)"
+    break
+  end
+
+  set dy = $1 + zero(x) ; # set error to be correct
+  fit1d_irls x y 0 -dy dy -wt wt -mask mask -use-median
+
+  subset ygood = y where not(mask)
+
+  vstat y
+  vstat ygood
+
+  histogram wt Nwt 0 1 0.005 -range dw
+  vstat wt
+
+  subset wts = wt where (wt < 0.3*$MEDIAN)
+  echo "0.3 of MEDIAN : wts[]"
+
+  subset wts = wt where (wt < 0.3*$MEAN)
+  echo "0.3 of MEAN : wts[]"
+
+  dev -n 0; resize 1200 600
+  label -fn courier 24; 
+  section a 0.4 0.0 0.6 1.0; lim x y; clear; box -ypad 0.1 -xpad 3.2 -labelpadx 2.5 -labels 1001; label -x sequence +y value +x "red: clipped, blue: unclipped"; 
+  plot x y; plot -c blue -pt 7 x y where not(mask); plot -c red -pt 7 -lw 2 x y where mask
+
+  section b 0.0 0.0 0.4 1.0; lim dw Nwt; box +ypad 0.1 -xpad 3.2 -labelpadx 2.5; label -x "weight" -y "Npoints"; plot -x 1 dw Nwt
+  png -name $2
+end
+
+## NOTE: this is not a TAP test
+macro cliptest
+
+  create x 0 100
+  gaussdev y x[] 0 1.0   ; # mean of 0, sigma of 1
+
+  if (1)
+    y[10] = 5.0
+    y[20] = 7.0
+    y[30] = 4.0
+  end
+
+  cliptest.plot 1.0 irls.sample.v0.png
+
+  cliptest.plot 0.1 irls.sample.v1.png
+
+  cliptest.plot 0.01 irls.sample.v2.png
+end
+
+## NOTE: this is not a TAP test
+macro outlier.test
+  if ($0 != 2)
+    echo "USAGE: outlier.test (errorbar)"
+    break
+  end
+
+  create x 0 100
+
+  delete C0fit dC0fit Cnfit Mfit dMfit
+  for i 0 300
+    gaussdev y x[] 0 1.0   ; # mean of 0, sigma of 1
+    
+    if (0)
+      y[10] = 5.0
+      y[20] = 7.0
+      y[30] = 4.0
+    end
+    
+    set dy = $1 + zero(x) ; # set error to be correct
+    fit1d_irls -q x y 0 -dy dy -wt wt -mask mask -use-median -Nboot 1000
+    concat $C0 C0fit
+    concat $dC0 dC0fit
+    concat $Cnfit Cnfit
+
+    vstat -q y
+    concat $MEAN Mfit
+    concat {$SIGMA / sqrt($NPTS)} dMfit
+  end
+
+  vstat C0fit
+  vstat dC0fit
+  vstat Cnfit
+  vstat Mfit
+  vstat dMfit
+end
+
+# fit a line without errors
+macro test1
+ $PASS = 1
+ break -auto off
+
+ delete -q x y
+
+ create x 0 100
+ set y = 3 + 5*x
+ fit -q x y 1
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 1e-5)
+   $PASS = 0
+ end
+end
+
+# fit a line with errors
+macro test2
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ fit -q x y 1
+
+ if ($Cn != 1)
+   $PASS = 0
+   echo "wrong number of elements : $Cn"
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+   echo "wrong value for C0 : $C0"
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+   echo "wrong value for C1 : $C1"
+ end
+end
+
+# fit a line with errors and weights
+macro test3
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ set dy = 0.1 + zero(x)
+ fit -q x y 1 -dy dy
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+ end
+end
+
+# fit a line with errors, weights, and outliers 
+macro test4
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x + dy
+ set dy = 0.1 + zero(x)
+ y[5] = 23
+ y[20] = -10
+ y[50] = 0.0
+ fit -q x y 1 -dy dy -clip 3 3
+
+ if ($Cn != 1)
+   $PASS = 0
+ end
+ if ($Cnv != 97)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic without errors
+macro test5
+ $PASS = 1
+ break -auto off
+
+ delete -q x y
+
+ create x 0 100
+ set y = 3 + 5*x - 4*x^2
+ fit -q x y 2
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 1e-5)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 1e-5)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors
+macro test6
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ fit -q x y 2
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.06)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors and weights
+macro test7
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ set dy = 0.1 + zero(x)
+ fit -q x y 2 -dy dy
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.06)
+   $PASS = 0
+ end
+end
+
+# fit a quadratic with errors, weights, and outliers 
+macro test8
+ $PASS = 1
+ break -auto off
+
+ delete -q x y dy
+
+ create x 0 100
+ set dy = 0.1*rnd(x) - 0.05
+ set y = 3 + 5*x - 4*x^2 + dy
+ set dy = 0.1 + zero(x)
+ y[5] = 23
+ y[20] = -10
+ y[50] = 0.0
+
+ # it takes 4 iterations to successfully reject the outliers above...
+ fit -q x y 2 -dy dy -clip 3 4
+
+ if ($Cn != 2)
+   $PASS = 0
+ end
+ if ($Cnv != 97)
+   $PASS = 0
+ end
+ if (abs($C0 - 3) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C1 - 5) > 0.06)
+   $PASS = 0
+ end
+ if (abs($C2 + 4) > 0.06)
+   $PASS = 0
+ end
+end
Index: trunk/Ohana/src/opihi/dvo/imbox.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/imbox.c	(revision 39693)
+++ trunk/Ohana/src/opihi/dvo/imbox.c	(revision 39926)
@@ -15,4 +15,17 @@
 
   if (!style_args (&graphmode, &argc, argv, &kapa)) return FALSE;
+
+  char *xaxis = NULL;
+  if ((N = get_argument (argc, argv, "-xaxis"))) {
+    remove_argument (N, &argc, argv);
+    xaxis = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  char *yaxis = NULL;
+  if ((N = get_argument (argc, argv, "-yaxis"))) {
+    remove_argument (N, &argc, argv);
+    yaxis = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
 
   SOLO_PHU = FALSE;
@@ -61,14 +74,29 @@
     // XXX currently, image uses an unsigned short for NX,XY. this is rather restrictive
     // and needs to be at least checked.
-    haveNx = gfits_scan (&header, "IMNAXIS1",   "%d", 1, &Nx);
-    haveNy = gfits_scan (&header, "IMNAXIS2",   "%d", 1, &Ny);
+    haveNx = FALSE;
+    if (xaxis) {
+      haveNx = gfits_scan (&header, xaxis, "%d", 1, &Nx);
+    }
+    if (!haveNx) {
+      haveNx = gfits_scan (&header, "IMNAXIS1",   "%d", 1, &Nx);
+    } 
+    if (!haveNx) {
+	haveNx = gfits_scan (&header, "ZNAXIS1",   "%d", 1, &Nx);
+    }
+    if (!haveNx) {
+	haveNx = gfits_scan (&header, "NAXIS1",   "%d", 1, &Nx);
+    }
 
-    if (!haveNx && !haveNy) {
-	haveNx = gfits_scan (&header, "ZNAXIS1",   "%d", 1, &Nx);
+    haveNy = FALSE;
+    if (yaxis) {
+      haveNy = gfits_scan (&header, yaxis, "%d", 1, &Ny);
+    }
+    if (!haveNy) {
+      haveNy = gfits_scan (&header, "IMNAXIS2",   "%d", 1, &Ny);
+    }
+    if (!haveNy) {
 	haveNy = gfits_scan (&header, "ZNAXIS2",   "%d", 1, &Ny);
     }
-
-    if (!haveNx && !haveNy) {
-	haveNx = gfits_scan (&header, "NAXIS1",   "%d", 1, &Nx);
+    if (!haveNy) {
 	haveNy = gfits_scan (&header, "NAXIS2",   "%d", 1, &Ny);
     }
@@ -137,4 +165,6 @@
   free (Xvec.elements.Flt);
   free (Yvec.elements.Flt);
+  if (xaxis) free (xaxis);
+  if (yaxis) free (yaxis);
   return (TRUE);
 
Index: trunk/Ohana/src/opihi/dvo/imdense.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/imdense.c	(revision 39693)
+++ trunk/Ohana/src/opihi/dvo/imdense.c	(revision 39926)
@@ -4,5 +4,4 @@
 int imdense (int argc, char **argv) {
   
-  long A, B;
   off_t i, Nimage;
   int kapa, N, status, NPTS;
@@ -27,7 +26,5 @@
   Rmax = graphmode.coords.crval1 + 182.0;
   
-  A = time(NULL);
-  for (B = 0; A == time(NULL); B++);
-  srand48(B);
+  // srand48() is called by startup.c
 
   N = 0;
Index: trunk/Ohana/src/opihi/dvo/skycat.c
===================================================================
--- trunk/Ohana/src/opihi/dvo/skycat.c	(revision 39693)
+++ trunk/Ohana/src/opihi/dvo/skycat.c	(revision 39926)
@@ -78,6 +78,10 @@
       if (table) {
 	int hostID = (regions[i][0].hostFlags & DATA_USE_BCK) ? regions[i][0].backupID : regions[i][0].hostID;
-	int index = table->index[hostID];
-	snprintf (hostfile, 1024, "%s/%s.cpt", table->hosts[index].pathname, regions[i][0].name);
+	if (hostID) {
+	  int index = table->index[hostID];
+	  snprintf (hostfile, 1024, "%s/%s.cpt", table->hosts[index].pathname, regions[i][0].name);
+	} else {
+	  strcpy (hostfile, skylist[0].filename[i]);
+	}
       } else {
 	strcpy (hostfile, skylist[0].filename[i]);
Index: trunk/Ohana/src/opihi/lib.data/style_args.c
===================================================================
--- trunk/Ohana/src/opihi/lib.data/style_args.c	(revision 39693)
+++ trunk/Ohana/src/opihi/lib.data/style_args.c	(revision 39926)
@@ -29,5 +29,5 @@
   if ((N = get_argument (*argc, argv, "-lt"))) {
     remove_argument (N, argc, argv);
-    graphmode[0].ltype = atof(argv[N]);
+    graphmode[0].ltype = KapaLineTypeFromString(argv[N]);
     remove_argument (N, argc, argv);
   }
@@ -39,5 +39,5 @@
   if ((N = get_argument (*argc, argv, "-pt"))) {
     remove_argument (N, argc, argv);
-    graphmode[0].ptype = atof(argv[N]);
+    graphmode[0].ptype = KapaPointStyleFromString(argv[N]);
     remove_argument (N, argc, argv);
   }
@@ -63,5 +63,5 @@
   if ((N = get_argument (*argc, argv, "-x"))) {
     remove_argument (N, argc, argv);
-    graphmode[0].style = atof(argv[N]);
+    graphmode[0].style = KapaPlotStyleFromString(argv[N]);
     remove_argument (N, argc, argv);
   }
Index: trunk/Ohana/src/opihi/lib.shell/startup.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/startup.c	(revision 39693)
+++ trunk/Ohana/src/opihi/lib.shell/startup.c	(revision 39926)
@@ -51,4 +51,15 @@
     gfits_set_unsign_mode (FALSE);
     
+    set_variable ("M_PI", M_PI);
+    set_variable ("M_E",  M_E);
+    set_variable ("M_c",  299792459.0); // meter / second
+    set_variable ("M_c_cgs", 29979245900.0); // cm / second
+
+    set_variable ("M_h",  6.62607004e-34); // meter^2 kg / second (J s)
+    set_variable ("M_h_cgs",  6.62607004e-27); // erg s
+
+    set_variable ("M_kB",  1.38064853e-23); // J / K
+    set_variable ("M_kB_cgs",  1.38064853e-16); // erg / K
+
   /* check history file permission */
   {
Index: trunk/Ohana/src/photdbc/src/make_subcatalog.c
===================================================================
--- trunk/Ohana/src/photdbc/src/make_subcatalog.c	(revision 39693)
+++ trunk/Ohana/src/photdbc/src/make_subcatalog.c	(revision 39926)
@@ -7,5 +7,5 @@
   int found;
   off_t i, j, k, offset;
-  off_t NAVERAGE, NMEASURE, Naverage, Nmeasure, Nm, Nsecfilt;
+  off_t Nm, Nsecfilt;
   double mag, minMag, minSigma;
   int keep, *secKeep;
@@ -27,10 +27,18 @@
 
   /* we are moving only the subset of measurements from catalog[0] to subcatalog[0] */
-  NAVERAGE = 50;
-  NMEASURE = 1000;
-  Nmeasure = Naverage = 0;
+  off_t NAVERAGE = 50;   off_t Naverage = 0;
+  off_t NMEASURE = 1000; off_t Nmeasure = 0;
+  off_t NLENSING = 1000; off_t Nlensing = 0;
+  off_t NLENSOBJ = 1000; off_t Nlensobj = 0;
+  off_t NSTARPAR = 1000; off_t Nstarpar = 0;
+  off_t NGALPHOT = 1000; off_t Ngalphot = 0;
+
   REALLOCATE (subcatalog[0].average, Average, NAVERAGE);
   REALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*Nsecfilt);
   REALLOCATE (subcatalog[0].measure, Measure, NMEASURE);
+  REALLOCATE (subcatalog[0].lensing, Lensing, NLENSING);
+  REALLOCATE (subcatalog[0].lensobj, Lensobj, NLENSOBJ);
+  REALLOCATE (subcatalog[0].starpar, StarPar, NSTARPAR);
+  REALLOCATE (subcatalog[0].galphot, GalPhot, NGALPHOT);
 
   for (i = 0; i < catalog[0].Naverage; i++) {
@@ -39,5 +47,5 @@
     // XXX: temporary check make sure that this object belongs in this region
     // used to fix the pole area in the reference catalog
-    {
+    if (0) {
         double R = catalog[0].average[i].R;
         double D = catalog[0].average[i].D;
@@ -177,4 +185,80 @@
     subcatalog[0].average[Naverage].Nmissing = 0;
     subcatalog[0].average[Naverage].Nmeasure = Nm;
+
+    // **** lensing
+    Nm = 0;
+    subcatalog[0].average[Naverage].lensingOffset = Nlensing;
+    for (j = 0; j < catalog[0].average[i].Nlensing; j++) {
+
+      offset = catalog[0].average[i].lensingOffset + j;
+
+      subcatalog[0].lensing[Nlensing]        = catalog[0].lensing[offset];
+      subcatalog[0].lensing[Nlensing].averef = Naverage;
+
+      Nlensing ++;
+      Nm ++;
+      if (Nlensing == NLENSING) {
+	NLENSING += 1000;
+	REALLOCATE (subcatalog[0].lensing, Lensing, NLENSING);
+      }
+    }
+    subcatalog[0].average[Naverage].Nlensing = Nm;
+
+    // **** lensobj
+    Nm = 0;
+    subcatalog[0].average[Naverage].lensobjOffset = Nlensobj;
+    for (j = 0; j < catalog[0].average[i].Nlensobj; j++) {
+
+      offset = catalog[0].average[i].lensobjOffset + j;
+
+      subcatalog[0].lensobj[Nlensobj]        = catalog[0].lensobj[offset];
+
+      Nlensobj ++;
+      Nm ++;
+      if (Nlensobj == NLENSOBJ) {
+	NLENSOBJ += 1000;
+	REALLOCATE (subcatalog[0].lensobj, Lensobj, NLENSOBJ);
+      }
+    }
+    subcatalog[0].average[Naverage].Nlensobj = Nm;
+
+    // **** starpar
+    Nm = 0;
+    subcatalog[0].average[Naverage].starparOffset = Nstarpar;
+    for (j = 0; j < catalog[0].average[i].Nstarpar; j++) {
+
+      offset = catalog[0].average[i].starparOffset + j;
+
+      subcatalog[0].starpar[Nstarpar]        = catalog[0].starpar[offset];
+      subcatalog[0].starpar[Nstarpar].averef = Naverage;
+
+      Nstarpar ++;
+      Nm ++;
+      if (Nstarpar == NSTARPAR) {
+	NSTARPAR += 1000;
+	REALLOCATE (subcatalog[0].starpar, StarPar, NSTARPAR);
+      }
+    }
+    subcatalog[0].average[Naverage].Nstarpar = Nm;
+
+    // **** galphot
+    Nm = 0;
+    subcatalog[0].average[Naverage].galphotOffset = Ngalphot;
+    for (j = 0; j < catalog[0].average[i].Ngalphot; j++) {
+
+      offset = catalog[0].average[i].galphotOffset + j;
+
+      subcatalog[0].galphot[Ngalphot]        = catalog[0].galphot[offset];
+      subcatalog[0].galphot[Ngalphot].averef = Naverage;
+
+      Ngalphot ++;
+      Nm ++;
+      if (Ngalphot == NGALPHOT) {
+	NGALPHOT += 1000;
+	REALLOCATE (subcatalog[0].galphot, GalPhot, NGALPHOT);
+      }
+    }
+    subcatalog[0].average[Naverage].Ngalphot = Nm;
+
     Naverage ++;
     if (Naverage == NAVERAGE) {
@@ -187,7 +271,17 @@
   REALLOCATE (subcatalog[0].measure, Measure, MAX (Nmeasure, 1));
   REALLOCATE (subcatalog[0].secfilt, SecFilt, Nsecfilt*MAX (Naverage, 1));
+  REALLOCATE (subcatalog[0].lensing, Lensing, MAX (Nlensing, 1));
+  REALLOCATE (subcatalog[0].lensobj, Lensobj, MAX (Nlensobj, 1));
+  REALLOCATE (subcatalog[0].starpar, StarPar, MAX (Nstarpar, 1));
+  REALLOCATE (subcatalog[0].galphot, GalPhot, MAX (Ngalphot, 1));
+
   subcatalog[0].Naverage = Naverage;
   subcatalog[0].Nmeasure = Nmeasure;
   subcatalog[0].Nsecfilt = Nsecfilt;
+  subcatalog[0].Nlensing = Nlensing;
+  subcatalog[0].Nlensobj = Nlensobj;
+  subcatalog[0].Nstarpar = Nstarpar;
+  subcatalog[0].Ngalphot = Ngalphot;
+
   subcatalog[0].Nsecfilt_mem = Naverage * Nsecfilt;
 
Index: trunk/Ohana/src/photdbc/src/photdbc_catalogs.c
===================================================================
--- trunk/Ohana/src/photdbc/src/photdbc_catalogs.c	(revision 39693)
+++ trunk/Ohana/src/photdbc/src/photdbc_catalogs.c	(revision 39926)
@@ -26,5 +26,9 @@
     incatalog.filename  = hostID ? hostfile : skylist[0].filename[i];
     incatalog.Nsecfilt = GetPhotcodeNsecfilt ();
-    incatalog.catflags = DVO_LOAD_AVERAGE | DVO_LOAD_MEASURE | DVO_LOAD_SECFILT;
+
+    incatalog.catflags    = DVO_LOAD_AVERAGE | DVO_LOAD_SECFILT;
+    incatalog.catflags   |= DVO_LOAD_MEASURE | DVO_LOAD_MISSING;
+    incatalog.catflags   |= DVO_LOAD_LENSING | DVO_LOAD_LENSOBJ;
+    incatalog.catflags   |= DVO_LOAD_STARPAR | DVO_LOAD_GALPHOT;
 
     // an error exit status here is a significant error
@@ -57,5 +61,9 @@
     outcatalog.catcompress = CATCOMPRESS ? dvo_catalog_catcompress (CATCOMPRESS) : incatalog.catcompress; // set the default catcompress from config data
     outcatalog.Nsecfilt    = incatalog.Nsecfilt;                 // inherit from the incatalog
-    outcatalog.catflags    = DVO_LOAD_AVERAGE | DVO_LOAD_MEASURE | DVO_LOAD_MISSING | DVO_LOAD_SECFILT;
+
+    outcatalog.catflags    = DVO_LOAD_AVERAGE | DVO_LOAD_SECFILT;
+    outcatalog.catflags   |= DVO_LOAD_MEASURE | DVO_LOAD_MISSING;
+    outcatalog.catflags   |= DVO_LOAD_LENSING | DVO_LOAD_LENSOBJ;
+    outcatalog.catflags   |= DVO_LOAD_STARPAR | DVO_LOAD_GALPHOT;
 
     // output catalogs always represent the same skyregions as the input catalogs
Index: trunk/Ohana/src/relastro/include/relastro.h
===================================================================
--- trunk/Ohana/src/relastro/include/relastro.h	(revision 39693)
+++ trunk/Ohana/src/relastro/include/relastro.h	(revision 39926)
@@ -33,5 +33,5 @@
 typedef enum {OP_NONE, OP_IMAGES, OP_HIGH_SPEED, OP_MERGE_SOURCE, OP_UPDATE_OBJECTS, OP_UPDATE_OFFSETS, OP_LOAD_OBJECTS, OP_HPM, OP_PARALLEL_REGIONS, OP_PARALLEL_IMAGES, OP_REPAIR_STACKS, OP_REPAIR_WARPS, OP_REPAIR_OBJECT_ID} RelastroOp;
 
-typedef enum {TARGET_NONE, TARGET_SIMPLE, TARGET_CHIPS, TARGET_MOSAICS} FitTarget;
+typedef enum {TARGET_NONE, TARGET_SIMPLE, TARGET_CHIPS, SET_CHIPS, TARGET_MOSAICS} FitTarget;
 
 typedef enum {
@@ -144,4 +144,6 @@
   int Nfit;
   int converged;
+  int useWeight;
+
 } FitAstromResult;
 
@@ -296,5 +298,5 @@
 } CheckMeasureResult;
 
-# define ID_MEAS_OBJECT_HAS_2MASS ID_MEAS_POOR_PHOTOM
+// # define ID_MEAS_OBJECT_HAS_2MASS ID_MEAS_POOR_PHOTOM
 
 /* global variables set in parameter file */
@@ -315,4 +317,5 @@
 int    PARALLEL_REGIONS_MANUAL;
 char  *MANUAL_UNIQUER;
+int    CATCH_UP;
 
 int          HOST_ID;
@@ -352,4 +355,7 @@
 int    VERBOSE2;
 
+float  TEST_SCALE;
+char  *GALAXY_MODEL;
+
 int    USE_FIXED_PIXCOORDS;
 int    USE_GALAXY_MODEL;
@@ -363,5 +369,18 @@
 int    USE_IMAGE_COORDS_FOR_REPAIR;
 int    USE_ALL_IMAGES;
+int    KEEP_ALL_IMAGES_RA;
 int    CHECK_MEASURE_TO_IMAGE;
+
+int    SKIP_PS1_CHIP;
+int    SKIP_PS1_STACK;
+int    SKIP_HSC;
+int    SKIP_CFH;
+
+int    UPDATE_PS1_STACK_MEASURE;
+int    UPDATE_PS1_CHIP_MEASURE;
+int    UPDATE_HSC_MEASURE;
+int    UPDATE_CFH_MEASURE;
+
+int    APPLY_PROPER_MOTION;
 
 int    RESET;
@@ -383,4 +402,9 @@
 int    CHIPMAP;
 
+int    *ChipMapLoop;
+int    *ChipOrderLoop;
+char   *ChipMapLoopStr;
+char   *ChipOrderLoopStr;
+
 int    N_BOOTSTRAP_SAMPLES;
 
@@ -407,7 +431,11 @@
 
 float *LoopWeight2MASS;
+char *LoopWeight2MASSstr;
+
 float *LoopWeightTycho;
-char *LoopWeight2MASSstr;
 char *LoopWeightTychostr;
+
+float *LoopWeightGAIA;
+char *LoopWeightGAIAstr;
 
 int ImagSelect;
@@ -433,4 +461,6 @@
 
 FitMode FIT_MODE;
+int USE_IRLS;
+int ALLOW_IRLS;
 
 RelastroOp RELASTRO_OP;
@@ -498,5 +528,5 @@
 void          initGridBins        PROTO((Catalog *catalog, int Ncatalog));
 void          initImageBins       PROTO((Catalog *catalog, int Ncatalog, int FULLINIT));
-void          initImages          PROTO((Image *input, off_t *line_number, off_t N));
+void          initImages          PROTO((Image *input, off_t *line_number, off_t N, int isSubset));
 void          freeImages          PROTO((char *dbImagePtr));
 void          initMosaicBins      PROTO((Catalog *catalog, int Ncatalog));
@@ -744,4 +774,6 @@
 int isGPC1stack (int photcode);
 int isGPC1warp (int photcode);
+int isHSCchip (int photcode);
+int isCFHchip (int photcode);
 
 int save_astrom_table ();
Index: trunk/Ohana/src/relastro/src/BootstrapOps.c
===================================================================
--- trunk/Ohana/src/relastro/src/BootstrapOps.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/BootstrapOps.c	(revision 39926)
@@ -77,21 +77,21 @@
     case FIT_RESULT_RA:
       // result->Ro = median;
-      result->dRo = sigma;
+      result->dRo = MAX(sigma, result->dRo);
       break;
     case FIT_RESULT_DEC:
       // result->Do = median;
-      result->dDo = sigma;
+      result->dDo = MAX(sigma, result->dDo);
       break;
     case FIT_RESULT_uR:
       // result->uR = median;
-      result->duR = sigma;
+      result->duR = MAX(sigma, result->duR);
       break;
     case FIT_RESULT_uD:
       // result->uD = median;
-      result->duD = sigma;
+      result->duD = MAX(sigma, result->duD);
       break;
     case FIT_RESULT_PLX:
       // result->p = median;
-      result->dp = sigma;
+      result->dp = MAX(sigma, result->dp);
       break;
     default:
Index: trunk/Ohana/src/relastro/src/BrightCatalog.c
===================================================================
--- trunk/Ohana/src/relastro/src/BrightCatalog.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/BrightCatalog.c	(revision 39926)
@@ -353,8 +353,8 @@
   /*** MeasureTiny ***/
   {
-    ohana_memcheck (1);
+    // ohana_memcheck (1);
     gfits_create_table_header (&theader, "BINTABLE", "MEASURE_TINY");
 
-    ohana_memcheck (1);
+    // ohana_memcheck (1);
 
     gfits_define_bintable_column (&theader, "D", "RA",       "ra",                         "degrees", 1.0, 0.0);
@@ -429,6 +429,6 @@
     gfits_set_bintable_column (&theader, &ftable, "RA",   	R,         catalog->Nmeasure);
 
-    fprintf (stderr, "--------------- after set_bintable RA --------------");
-    ohana_memdump_file (stderr, TRUE);
+    // fprintf (stderr, "--------------- after set_bintable RA --------------");
+    // ohana_memdump_file (stderr, TRUE);
     
     gfits_set_bintable_column (&theader, &ftable, "DEC",  	D,         catalog->Nmeasure);
Index: trunk/Ohana/src/relastro/src/ConfigInit.c
===================================================================
--- trunk/Ohana/src/relastro/src/ConfigInit.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/ConfigInit.c	(revision 39926)
@@ -84,11 +84,4 @@
   SetZeroPoint (25.0);
 
-  if (USE_GALAXY_MODEL) {
-    if (!InitGalaxyModel ("FEAST-HIPPARCOS")) {
-      fprintf (stderr, "failed to init galaxy model\n");
-      exit (2);
-    }
-  }
-
   FreeConfigFile();
   free (config);
Index: trunk/Ohana/src/relastro/src/FitAstromOps.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitAstromOps.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/FitAstromOps.c	(revision 39926)
@@ -257,4 +257,8 @@
   fit->converged = FALSE;
   
+  // this is an input value
+  // if true, use the IRLS modified weight
+  fit->useWeight = FALSE;
+
   return;
 }
Index: trunk/Ohana/src/relastro/src/FitChip.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitChip.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/FitChip.c	(revision 39926)
@@ -78,5 +78,5 @@
       order_use = MIN(MIN(order_use, CHIPMAP), 6); // can only go up to 6th order map (can be user limited)
     } else {
-      order_use = MIN(order_use, 3); // can only go up to 3rd order for polynomials
+      order_use = MIN(MIN(order_use, CHIPORDER), 3); // can only go up to 3rd order for polynomials
     }
 
@@ -206,9 +206,26 @@
   if (VERBOSE2) fprintf (stderr, "fit sigma: %f (%f, %f) : full: %f (%f, %f), scatter limit: %f (%d full, %d bright, %d fit, %d all) (%d %d %d %d %d)\n", dRsig, dLsig, dMsig, dRsigFull, dLsigFull, dMsigFull, dRmax, NstatFull, Nstat, fit[0].Npts, Nmatch, nMask1, nMask2, nMask3, nMask4, nMask5);
 
-  image[0].dXpixSys = dLsig;
-  image[0].dYpixSys = dMsig;
+  // need to convert dLsig, dMsig back to pixel scale (or up to arcsec)
+
+  float plateScale;
+  if (image[0].coords.mosaic) {
+    // NOTE: for the full pixel to sky plate scale, use this:
+    // float plateScaleX = 3600.0*image[0].coords.mosaic->cdelt1*image[0].coords.cdelt1;
+    // float plateScaleY = 3600.0*image[0].coords.mosaic->cdelt2*image[0].coords.cdelt2;
+
+    // since we are compare L,M values, just need to compensate for focal plate to sky:
+    float plateScaleX = 3600.0*fabs(image[0].coords.mosaic->cdelt1);
+    float plateScaleY = 3600.0*fabs(image[0].coords.mosaic->cdelt2);
+    plateScale = 0.5*(plateScaleX + plateScaleY);
+  } else {
+    // since we are compare L,M values, just need to compensate for arcsec vs degrees:
+    plateScale = 3600.0;
+  }
+
+  image[0].dXpixSys = plateScale*dLsig;
+  image[0].dYpixSys = plateScale*dMsig;
   image[0].nFitAstrom = fit[0].Npts;
 
-  // fprintf (stderr, "%s %6.3f %4d %4d\n", image[0].name, image[0].refColor, Ncolor, image[0].nFitAstrom);
+  if (VERBOSE2) fprintf (stderr, "%s | %6.3f %6.3f | %4d %4d | %6.3f %6.3f\n", image[0].name, image[0].refColorRed, image[0].refColorBlue, Ncolor, image[0].nFitAstrom, image[0].dXpixSys, image[0].dYpixSys);
 
   if (fit) fit_free (fit);
Index: trunk/Ohana/src/relastro/src/FitPM.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPM.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/FitPM.c	(revision 39926)
@@ -25,4 +25,5 @@
   }
 
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPM_MinChisq (fit, data, points, Npoints)) return FALSE;
   if (!FitPM_SetChisq (fit, data, points, Npoints)) return FALSE;
@@ -47,4 +48,5 @@
   
   // Solve OLS equation  
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPM_MinChisq(fit, data, points, Npoints)) {
     return(FALSE);
@@ -69,5 +71,5 @@
 
   // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
+  // double sigma_hat = 0.0; // save for the error model
   int converged = FALSE;
   int iterations = 0;
@@ -90,4 +92,5 @@
 
     // Solve with the new weights
+    fit->useWeight = TRUE; // Reweighted Least Squares
     if (!FitPM_MinChisq(fit, data, points, Npoints)) {
 
@@ -104,5 +107,5 @@
 	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
       }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+      // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
       break;
     }
@@ -119,5 +122,5 @@
       points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
     }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+    // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
     
     // Check convergence
@@ -159,38 +162,15 @@
   // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
   if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].Wx);
-      by += SQ(points[i].Wy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].duR = sqrt(data->Cov[1][1]);
-    fit[0].dDo = sqrt(data->Cov[2][2]);
-    fit[0].duD = sqrt(data->Cov[3][3]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].duR *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
-    fit[0].duD *= sigma_final_y;
+    FitAstromResult fitErrors;
+    FitAstromResultInit (&fitErrors);
+    fitErrors.useWeight = FALSE; 
+
+    FitPM_MinChisq(&fitErrors, data, points, Npoints);
+
+    // we use the errors from a simple OLS, ignoring masked points
+    fit[0].dRo = fitErrors.dRo;
+    fit[0].duR = fitErrors.duR;
+    fit[0].dDo = fitErrors.dDo;
+    fit[0].duD = fitErrors.duD;
   }
 
@@ -212,6 +192,11 @@
     Nfit ++;
 
-    wx = points[i].qx;
-    wy = points[i].qy;
+    if (fit->useWeight) {
+      wx = points[i].qx;
+      wy = points[i].qy;
+    } else {
+      wx = points[i].Qx;
+      wy = points[i].Qy;
+    }
 
     Wx += wx;
Index: trunk/Ohana/src/relastro/src/FitPM_IRLS.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPM_IRLS.c	(revision 39693)
+++ 	(revision )
@@ -1,269 +1,0 @@
-# include "relastro.h"
-
-// These should probably be tunable:
-# define MAX_ITERATIONS 10
-# define FIT_TOLERANCE 1e-4
-# define FLT_TOLERANCE 1e-6
-# define WEIGHT_THRESHOLD 0.3
-
-int FitPM_IRLS (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints, int VERBOSE) {
-
-  int i,j;
-
-  int Ndof = 2 * Npoints - data->Nterms;
-  
-  // Convert the measurement errors into initial weights.
-  for (i = 0; i < Npoints; i++) {
-    points[i].Wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1 / SQ(points[i].dX);
-    points[i].Wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1 / SQ(points[i].dY);
-  }
-  
-  // Solve OLS equation  
-  if (!FitPM_MinChisq(fit, data, points, Npoints)) {
-    return(FALSE);
-  }
-
-  // Calculate r vector of residuals and least squares sigma
-  double sigma_ols = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-    points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-    sigma_ols += SQ(points[i].rx) + SQ(points[i].ry);
-  }
-  sigma_ols = sqrt(sigma_ols / (float)Ndof);
-
-  // Save OLS covariance and Beta (solution vector, which is actually also saved in fit)
-  for (i = 0; i < data->Nterms; i++) {
-    for (j = 0; j < data->Nterms; j++) {
-      data->Cov[i][j] = data->A[i][j];
-    }
-    data->Beta[i] = data->B[i][0];
-  }
-
-  // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
-  int converged = FALSE;
-  int iterations = 0;
-
-  // modify the weight based on the distance from the previous fit.  try up to MAX_ITERATIONS.
-  // at the end "fit", has the last fit parameters
-  for (iterations = 0; !converged && (iterations < MAX_ITERATIONS); iterations ++) {
-    // Save Beta.
-    for (i = 0; i < data->Nterms; i ++) {
-      data->Beta_prev[i] = data->Beta[i];
-    }
-
-    // Assign weights based on the deviation
-    for (i = 0; i < Npoints; i++) {
-      points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-      points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-    }    
-
-    // Solve with the new weights
-    if (!FitPM_MinChisq(fit, data, points, Npoints)) {
-
-      // restore the last solution and break
-      fit->Ro = data->Beta_prev[0];
-      fit->uR = data->Beta_prev[1];
-      fit->Do = data->Beta_prev[2];
-      fit->uD = data->Beta_prev[3];
-      
-      // calculate the residuals:
-      for (i = 0; i < Npoints; i++) {
-	points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-	points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-      }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-      break;
-    }
-
-    // store the new Beta.
-    for (i = 0; i < data->Nterms; i++) {
-      data->Beta[i] = data->B[i][0];
-    }
-
-    // calculate the residuals:
-    for (i = 0; i < Npoints; i++) {
-      points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-      points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-      points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-    }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-    
-    // Check convergence
-    converged = TRUE;
-    for (i = 0; i < data->Nterms; i++) {
-      // if we are within FIT_TOLERANCE as a fractional error or FLT_TOLERANCE as an absolute error, we are good
-      if ((fabs(data->Beta[i] - data->Beta_prev[i]) > FIT_TOLERANCE * fabs(data->Beta[i])) && 
-	  (fabs(data->Beta[i] - data->Beta_prev[i]) > FLT_TOLERANCE)) {
-	converged = FALSE;
-      }
-    }
-  }
-  fit->converged = converged;
-
-  // calculate the weight thresholds to mask the bad points:
-  double Sum_Wx = 0.0;
-  double Sum_Wy = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-    points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-    
-    Sum_Wx += points[i].Wx;
-    Sum_Wy += points[i].Wy;
-  }
-  double WxThreshold = WEIGHT_THRESHOLD * Sum_Wx / (1.0 * Npoints);
-  double WyThreshold = WEIGHT_THRESHOLD * Sum_Wy / (1.0 * Npoints);
-
-  // set a mask (which can be used by the bootstrap resampling analysis)
-  for (i = 0; i < Npoints; i++) {
-    // keep if either is above threshold?
-    // drop if either is below threshold?
-    // points are marked as keep by default
-    if ((points[i].Wx < WxThreshold) || (points[i].Wy < WyThreshold)) {
-      points[i].mask = 1; // keep point if mask == 0
-    }
-  }
-
-  // this section calculates the formal error on the weighted fit using the covariance values
-  // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
-  if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].Wx);
-      by += SQ(points[i].Wy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].duR = sqrt(data->Cov[1][1]);
-    fit[0].dDo = sqrt(data->Cov[2][2]);
-    fit[0].duD = sqrt(data->Cov[3][3]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].duR *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
-    fit[0].duD *= sigma_final_y;
-  }
-
-  // count unmasked points and (optionally) add up the chi square for the fit
-  double chisq = 0.0;
-  fit[0].Nfit = 0;
-  for (i = 0; i < Npoints; i++) {
-    if (points[i].mask) continue;
-    fit[0].Nfit ++;
-      
-    if (data->getChisq) {
-      double Xf = fit[0].Ro + fit[0].uR*points[i].T;
-      double Yf = fit[0].Do + fit[0].uD*points[i].T;
-      double wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dX);
-      double wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dY);
-      chisq += SQ(points[i].X - Xf) * wx;
-      chisq += SQ(points[i].Y - Yf) * wy;
-    }
-  }
-    
-  // the reduced chisq is divided by (Ndof = 2*Nfit - Nterms)
-  fit[0].chisq = chisq / (2.0*fit[0].Nfit - data->Nterms);
-
-  return (TRUE);
-}
-
-int FitPM_MinChisq (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints) {
-
-  myAssert (data->Nterms == 4, "invalid fit arrays");
-
-  int i;
-  double wx, wy, Wx, Wy, Tx, Ty, Tx2, Ty2, Xs, Ys, XT, YT;
-  Wx = Wy = Tx = Ty = Tx2 = Ty2 = Xs = Ys = XT = YT = 0.0;
-
-  for (i = 0; i < Npoints; i++) {
-    if (points[i].mask) continue; // respect the mask if set
-
-    wx = points[i].Wx;
-    wy = points[i].Wy;
-
-    Wx += wx;
-    Wy += wy;
-
-    double TWx = points[i].T*wx;
-    double TWy = points[i].T*wy;
-
-    Tx += TWx;
-    Ty += TWy;
-    
-    Tx2 += points[i].T*TWx;
-    Ty2 += points[i].T*TWy;
-    
-    Xs += points[i].X*wx;
-    Ys += points[i].Y*wy;
-
-    XT += points[i].X*TWx;
-    YT += points[i].Y*TWy;
-  }
-
-  // X^T W X
-  data->A[0][0] = Wx;
-  data->A[0][1] = Tx;
-  data->A[0][2] = 0.0;
-  data->A[0][3] = 0.0;
-
-  data->A[1][0] = Tx;
-  data->A[1][1] = Tx2;
-  data->A[1][2] = 0.0;
-  data->A[1][3] = 0.0;
-
-  data->A[2][0] = 0.0;
-  data->A[2][1] = 0.0;
-  data->A[2][2] = Wy;
-  data->A[2][3] = Ty;
-
-  data->A[3][0] = 0.0;
-  data->A[3][1] = 0.0;
-  data->A[3][2] = Ty;
-  data->A[3][3] = Ty2;
-
-  // X^T W Y
-  data->B[0][0] = Xs;
-  data->B[1][0] = XT;
-  data->B[2][0] = Ys;
-  data->B[3][0] = YT;
-
-  if (!dgaussjordan (data->A, data->B, 4, 1)) {
-    return FALSE;
-  }
-
-  fit->Ro = data->B[0][0];
-  fit->uR = data->B[1][0];
-  fit->Do = data->B[2][0];
-  fit->uD = data->B[3][0];
-  fit->p  = 0.0;
-
-  fit->dRo = sqrt(data->A[0][0]);
-  fit->duR = sqrt(data->A[1][1]);
-  fit->dDo = sqrt(data->A[2][2]);
-  fit->duD = sqrt(data->A[3][3]);
-  fit->dp  = 0.0;
-
-  return TRUE;
-}
-
Index: trunk/Ohana/src/relastro/src/FitPMandPar.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPMandPar.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/FitPMandPar.c	(revision 39926)
@@ -25,4 +25,5 @@
   }
 
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPMandPar_MinChisq (fit, data, points, Npoints)) return FALSE;
   if (!FitPMandPar_SetChisq (fit, data, points, Npoints)) return FALSE;
@@ -47,4 +48,5 @@
   
   // Solve OLS equation: failure here means the chisq matrix is degenerate, give up entirely
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPMandPar_MinChisq(fit, data, points, Npoints)) {
     return(FALSE);
@@ -69,5 +71,5 @@
 
   // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
+  // double sigma_hat = 0.0; // save for the error model
   int converged = FALSE;
   int iterations = 0;
@@ -90,4 +92,5 @@
 
     // Solve with the new weights
+    fit->useWeight = TRUE; // Reweighted Least Squares
     if (!FitPMandPar_MinChisq(fit, data, points, Npoints)) {
 
@@ -105,5 +108,5 @@
 	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
       }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+      // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
       break;
     }
@@ -120,5 +123,5 @@
       points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
     }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+    // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
 
     // Check convergence
@@ -157,43 +160,19 @@
   }
 
-  // this section calculates the formal error on the weighted fit using the covariance values
-  // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
+  // this section calculates the formal error on the regular (unweighted) fit using the covariance values
+  // NOTE 20160929 : use only the unmasked points to calculate the error
   if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].Wx);
-      by += SQ(points[i].Wy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].duR = sqrt(data->Cov[1][1]);
-    fit[0].dDo = sqrt(data->Cov[2][2]);
-    fit[0].duD = sqrt(data->Cov[3][3]);
-    fit[0].dp  = sqrt(data->Cov[4][4]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].duR *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
-    fit[0].duD *= sigma_final_y;
-    fit[0].dp  *= sqrt(sigma_final_x * sigma_final_y);
+    FitAstromResult fitErrors;
+    FitAstromResultInit (&fitErrors);
+    fitErrors.useWeight = FALSE; 
+
+    FitPMandPar_MinChisq(&fitErrors, data, points, Npoints);
+
+    // we use the errors from a simple OLS, ignoring masked points
+    fit[0].dRo = fitErrors.dRo;
+    fit[0].duR = fitErrors.duR;
+    fit[0].dDo = fitErrors.dDo;
+    fit[0].duD = fitErrors.duD;
+    fit[0].dp  = fitErrors.dp;
   }
 
@@ -219,6 +198,11 @@
     Nfit ++;
 
-    wx = points[i].qx;
-    wy = points[i].qy;
+    if (fit->useWeight) {
+      wx = points[i].qx;
+      wy = points[i].qy;
+    } else {
+      wx = points[i].Qx;
+      wy = points[i].Qy;
+    }
 
     Wx += wx;
Index: trunk/Ohana/src/relastro/src/FitPMandPar_IRLS.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPMandPar_IRLS.c	(revision 39693)
+++ 	(revision )
@@ -1,302 +1,0 @@
-# include "relastro.h"
-# define OLD_METHOD 1
-
-// These should probably be tunable:
-# define MAX_ITERATIONS 10
-# define FIT_TOLERANCE 1e-4
-# define FLT_TOLERANCE 1e-6
-# define WEIGHT_THRESHOLD 0.3
-
-int FitPMandPar_IRLS (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints, int VERBOSE) {
-
-  int i,j;
-
-  int Ndof = 2 * Npoints - data->Nterms;
-  
-  // Convert the measurement errors into initial weights.
-  for (i = 0; i < Npoints; i++) {
-# if (OLD_METHOD)
-    points[i].Wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1 / SQ(points[i].dX);
-    points[i].Wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1 / SQ(points[i].dY);
-# else
-    points[i].Qx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1 / SQ(points[i].dX);
-    points[i].Qy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1 / SQ(points[i].dY);
-# endif
-    points[i].qx = points[i].Wx * points[i].Qx; // Wx, Wy start out at 1.0
-    points[i].qy = points[i].Wy * points[i].Qy; // Wx, Wy start out at 1.0
-  }
-  
-  // Solve OLS equation: failure here means the chisq matrix is degenerate, give up entirely
-  if (!weighted_LS_PLX(fit, data, points, Npoints, VERBOSE)) {
-    return(FALSE);
-  }
-
-  // Calculate r vector of residuals and least squares sigma
-  double sigma_ols = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro + points[i].pR * fit->p);
-    points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do + points[i].pD * fit->p);
-    sigma_ols += SQ(points[i].rx) + SQ(points[i].ry);
-  }
-  sigma_ols = sqrt(sigma_ols / (float)Ndof);
-  
-  // Save OLS covariance and Beta (solution vector, which is actually also saved in fit)
-  for (i = 0; i < data->Nterms; i++) {
-    for (j = 0; j < data->Nterms; j++) {
-      data->Cov[i][j] = data->A[i][j];
-    }
-    data->Beta[i] = data->B[i][0];
-  }
-
-  // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
-  int converged = FALSE;
-  int iterations = 0;
-
-  // modify the weight based on the distance from the previous fit.  try up to MAX_ITERATIONS.
-  // at the end "fit", has the last fit parameters
-  for (iterations = 0; !converged && (iterations < MAX_ITERATIONS); iterations ++) {
-    // Save Beta.
-    for (i = 0; i < data->Nterms; i ++) {
-      data->Beta_prev[i] = data->Beta[i];
-    }
-
-    // Assign weights based on the deviation
-    for (i = 0; i < Npoints; i++) {
-      points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-      points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-      points[i].qx = points[i].Wx * points[i].Qx;
-      points[i].qy = points[i].Wy * points[i].Qy;
-    }    
-
-    // Solve with the new weights
-    if (!weighted_LS_PLX(fit, data, points, Npoints, VERBOSE)) {
-
-      // restore the last solution and break
-      fit->Ro = data->Beta_prev[0];
-      fit->uR = data->Beta_prev[1];
-      fit->Do = data->Beta_prev[2];
-      fit->uD = data->Beta_prev[3];
-      fit->p  = data->Beta_prev[4];
-      
-      // calculate the residuals:
-      for (i = 0; i < Npoints; i++) {
-	points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro + points[i].pR * fit->p);
-	points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do + points[i].pD * fit->p);
-	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-      }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-      break;
-    }
-
-    // store the new Beta.
-    for (i = 0; i < data->Nterms; i++) {
-      data->Beta[i] = data->B[i][0];
-    }
-
-    // calculate the residuals:
-    for (i = 0; i < Npoints; i++) {
-      points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro + points[i].pR * fit->p);
-      points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do + points[i].pD * fit->p);
-      points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-    }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-
-    // Check convergence
-    converged = TRUE;
-    for (i = 0; i < data->Nterms; i++) {
-      // if we are within FIT_TOLERANCE as a fractional error or FLT_TOLERANCE as an absolute error, we are good
-      if ((fabs(data->Beta[i] - data->Beta_prev[i]) > FIT_TOLERANCE * fabs(data->Beta[i])) && 
-	  (fabs(data->Beta[i] - data->Beta_prev[i]) > FLT_TOLERANCE)) {
-	converged = FALSE;
-      }
-    }
-  }
-  fit->converged = converged;
-
-  // calculate the weight thresholds to mask the bad points:
-  double Sum_Wx = 0.0;
-  double Sum_Wy = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-    points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-    
-    Sum_Wx += points[i].Wx;
-    Sum_Wy += points[i].Wy;
-  }
-  double WxThreshold = WEIGHT_THRESHOLD * Sum_Wx / (1.0 * Npoints);
-  double WyThreshold = WEIGHT_THRESHOLD * Sum_Wy / (1.0 * Npoints);
-
-  // set a mask (which can be used by the bootstrap resampling analysis)
-  for (i = 0; i < Npoints; i++) {
-    // keep if either is above threshold?
-    // drop if either is below threshold?
-    // points are marked as keep by default
-    if ((points[i].Wx < WxThreshold) || (points[i].Wy < WyThreshold)) {
-      points[i].mask = 1; // keep point if mask == 0
-    }
-  }
-
-  // this section calculates the formal error on the weighted fit using the covariance values
-  // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
-  if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].qx);
-      by += SQ(points[i].qy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].duR = sqrt(data->Cov[1][1]);
-    fit[0].dDo = sqrt(data->Cov[2][2]);
-    fit[0].duD = sqrt(data->Cov[3][3]);
-    fit[0].dp  = sqrt(data->Cov[4][4]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].duR *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
-    fit[0].duD *= sigma_final_y;
-    fit[0].dp  *= sqrt(sigma_final_x * sigma_final_y);
-  }
-
-  // count unmasked points and (optionally) add up the chi square for the fit
-  double chisq = 0.0;
-  fit[0].Nfit = 0;
-  for (i = 0; i < Npoints; i++) {
-    if (points[i].mask) continue;
-    fit[0].Nfit ++;
-      
-    if (data->getChisq) {
-      double Xf = fit[0].Ro + fit[0].uR*points[i].T + fit[0].p*points[i].pR;
-      double Yf = fit[0].Do + fit[0].uD*points[i].T + fit[0].p*points[i].pD;
-      double wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dX);
-      double wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dY);
-      chisq += SQ(points[i].X - Xf) * wx;
-      chisq += SQ(points[i].Y - Yf) * wy;
-    }  
-  }
-    
-  // the reduced chisq is divided by Ndof = (2*Nfit - Nterms)
-  fit[0].chisq = chisq / (2.0*fit[0].Nfit - data->Nterms);
-  
-  return (TRUE);
-}
-
-int weighted_LS_PLX (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints, int VERBOSE) {
-
-  myAssert (data->Nterms == 5, "invalid fit arrays");
-
-  int i;
-  double wx, wy, Wx, Wy, Tx, Ty, Tx2, Ty2, Xs, Ys, XT, YT;
-  double PR, PD, PRT, PDT, PRX, PDY, PR2, PD2;
-
-  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 < Npoints; i++) {
-
-    // if (VERBOSE == 2) fprintf (stderr, "%f %f : %f %f : %f : %f %f\n", X[i], WX[i], Y[i], WY[i], T[i], pR[i], pD[i]);
-
-# if (OLD_METHOD)
-    wx = points[i].Wx;
-    wy = points[i].Wy;
-# else 
-    wx = points[i].Wx;
-    wy = points[i].Wy;
-# endif
-
-    Wx += wx;
-    Wy += wy;
-
-    Tx += points[i].T*wx;
-    Ty += points[i].T*wy;
-    
-    Tx2 += SQ(points[i].T)*wx;
-    Ty2 += SQ(points[i].T)*wy;
-    
-    PR += points[i].pR*wx;
-    PD += points[i].pD*wy;
-    
-    PRT += points[i].pR*points[i].T*wx;
-    PDT += points[i].pD*points[i].T*wy;
-    
-    PRX += points[i].pR*points[i].X*wx;
-    PDY += points[i].pD*points[i].Y*wy;
-    
-    PR2 += SQ(points[i].pR)*wx;
-    PD2 += SQ(points[i].pD)*wy;
-
-    Xs += points[i].X*wx;
-    Ys += points[i].Y*wy;
-
-    XT += points[i].X*points[i].T*wx;
-    YT += points[i].Y*points[i].T*wy;
-  }
-
-  data->A[0][0] = Wx;
-  data->A[0][1] = Tx;
-  data->A[0][2] = 0.0;
-  data->A[0][3] = 0.0;
-  data->A[0][4] = PR;
-
-  data->A[1][0] = Tx;
-  data->A[1][1] = Tx2;
-  data->A[1][2] = 0.0;
-  data->A[1][3] = 0.0;
-  data->A[1][4] = PRT;
-
-  data->A[2][0] = 0.0;
-  data->A[2][1] = 0.0;
-  data->A[2][2] = Wy;
-  data->A[2][3] = Ty;
-  data->A[2][4] = PD;
-
-  data->A[3][0] = 0.0;
-  data->A[3][1] = 0.0;
-  data->A[3][2] = Ty;
-  data->A[3][3] = Ty2;
-  data->A[3][4] = PDT;
-
-  data->A[4][0] = PR;
-  data->A[4][1] = PRT;
-  data->A[4][2] = PD;
-  data->A[4][3] = PDT;
-  data->A[4][4] = PR2 + PD2;
-
-  data->B[0][0] = Xs;
-  data->B[1][0] = XT;
-  data->B[2][0] = Ys;
-  data->B[3][0] = YT;
-  data->B[4][0] = PRX + PDY;
-
-  if (!dgaussjordan (data->A, data->B, 5, 1)) {
-    return FALSE;
-  }
-
-  fit->Ro = data->B[0][0];
-  fit->uR = data->B[1][0];
-  fit->Do = data->B[2][0];
-  fit->uD = data->B[3][0];
-  fit->p  = data->B[4][0];
-
-  return TRUE;
-}
Index: trunk/Ohana/src/relastro/src/FitPosPMfixed.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPosPMfixed.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/FitPosPMfixed.c	(revision 39926)
@@ -54,4 +54,5 @@
   }
 
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPosPMfixed_MinChisq (fit, data, points, Npoints)) {
     if (!FitPosPMfixed_Single (fit, points, Npoints)) return FALSE;
@@ -83,4 +84,5 @@
   
   // Solve OLS equation  
+  fit->useWeight = FALSE; // Ordinary Least Squares
   if (!FitPosPMfixed_MinChisq(fit, data, points, Npoints)) {
     return(FALSE);
@@ -105,5 +107,5 @@
 
   // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
+  // double sigma_hat = 0.0; // save for the error model
   int converged = FALSE;
   int iterations = 0;
@@ -126,4 +128,5 @@
 
     // Solve with the new weights
+    fit->useWeight = TRUE; // Reweighted Least Squares
     if (!FitPosPMfixed_MinChisq(fit, data, points, Npoints)) {
 
@@ -138,5 +141,5 @@
 	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
       }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+      // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
       break;
     }
@@ -153,5 +156,5 @@
       points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
     }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
+    // sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
     
     // Check convergence
@@ -193,34 +196,16 @@
   // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
   if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].Wx);
-      by += SQ(points[i].Wy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].dDo = sqrt(data->Cov[1][1]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
+    FitAstromResult fitErrors;
+    FitAstromResultInit (&fitErrors);
+    fitErrors.useWeight = FALSE; 
+
+    FitPosPMfixed_MinChisq(&fitErrors, data, points, Npoints);
+
+    // we use the errors from a simple OLS, ignoring masked points
+    fit[0].dRo = fitErrors.dRo;
+    fit[0].duR = fitErrors.duR;
+    fit[0].dDo = fitErrors.dDo;
+    fit[0].duD = fitErrors.duD;
+    fit[0].dp  = fitErrors.dp;
   }
 
@@ -242,6 +227,11 @@
     Nfit ++;
 
-    wx = points[i].qx;
-    wy = points[i].qy;
+    if (fit->useWeight) {
+      wx = points[i].qx;
+      wy = points[i].qy;
+    } else {
+      wx = points[i].Qx;
+      wy = points[i].Qy;
+    }
 
     Wx += wx;
Index: trunk/Ohana/src/relastro/src/FitPosPMfixed_IRLS.c
===================================================================
--- trunk/Ohana/src/relastro/src/FitPosPMfixed_IRLS.c	(revision 39693)
+++ 	(revision )
@@ -1,228 +1,0 @@
-# include "relastro.h"
-
-// These should probably be tunable:
-# define MAX_ITERATIONS 10
-# define FIT_TOLERANCE 1e-4
-# define FLT_TOLERANCE 1e-6
-# define WEIGHT_THRESHOLD 0.3
-
-int FitPosPMfixed_IRLS (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints, int VERBOSE) {
-
-  int i,j;
-
-  int Ndof = 2 * Npoints - data->Nterms;
-  
-  // Convert the measurement errors into initial weights.
-  for (i = 0; i < Npoints; i++) {
-    points[i].Wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1 / SQ(points[i].dX);
-    points[i].Wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1 / SQ(points[i].dY);
-  }
-  
-  // Solve OLS equation  
-  if (!weighted_LS_POS(fit, data, points, Npoints, VERBOSE)) {
-    return(FALSE);
-  }
-
-  // Calculate r vector of residuals and least squares sigma
-  double sigma_ols = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-    points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-    sigma_ols += SQ(points[i].rx) + SQ(points[i].ry);
-  }
-  sigma_ols = sqrt(sigma_ols / (float)Ndof);
-
-  // Save OLS covariance and Beta (solution vector, which is actually also saved in fit)
-  for (i = 0; i < data->Nterms; i++) {
-    for (j = 0; j < data->Nterms; j++) {
-      data->Cov[i][j] = data->A[i][j];
-    }
-    data->Beta[i] = data->B[i][0];
-  }
-
-  // Iteratively reweight and solve
-  double sigma_hat = 0.0; // save for the error model
-  int converged = FALSE;
-  int iterations = 0;
-
-  // modify the weight based on the distance from the previous fit.  try up to MAX_ITERATIONS.
-  // at the end "fit", has the last fit parameters
-  for (iterations = 0; !converged && (iterations < MAX_ITERATIONS); iterations ++) {
-    // Save Beta.
-    for (i = 0; i < data->Nterms; i ++) {
-      data->Beta_prev[i] = data->Beta[i];
-    }
-
-    // Assign weights based on the deviation
-    for (i = 0; i < Npoints; i++) {
-      points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-      points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-    }    
-
-    // Solve with the new weights
-    if (!weighted_LS_POS(fit, data, points, Npoints, VERBOSE)) {
-
-      // restore the last solution and break
-      fit->Ro = data->Beta_prev[0];
-      fit->Do = data->Beta_prev[1];
-      
-      // calculate the residuals:
-      for (i = 0; i < Npoints; i++) {
-	points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-	points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-	points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-      }
-      sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-      break;
-    }
-
-    // store the new Beta.
-    for (i = 0; i < data->Nterms; i++) {
-      data->Beta[i] = data->B[i][0];
-    }
-
-    // calculate the residuals:
-    for (i = 0; i < Npoints; i++) {
-      points[i].rx = points[i].X - (points[i].T * fit->uR + fit->Ro);
-      points[i].ry = points[i].Y - (points[i].T * fit->uD + fit->Do);
-      points[i].u = sqrt(SQ(points[i].rx / points[i].dX) + SQ(points[i].ry / points[i].dY));
-    }
-    sigma_hat = MedianAbsDeviation(points, Npoints) / 0.6745;
-    
-    // Check convergence
-    converged = TRUE;
-    for (i = 0; i < data->Nterms; i++) {
-      // if we are within FIT_TOLERANCE as a fractional error or FLT_TOLERANCE as an absolute error, we are good
-      if ((fabs(data->Beta[i] - data->Beta_prev[i]) > FIT_TOLERANCE * fabs(data->Beta[i])) && 
-	  (fabs(data->Beta[i] - data->Beta_prev[i]) > FLT_TOLERANCE)) {
-	converged = FALSE;
-      }
-    }
-  }
-  fit->converged = converged;
-
-  // calculate the weight thresholds to mask the bad points:
-  double Sum_Wx = 0.0;
-  double Sum_Wy = 0.0;
-  for (i = 0; i < Npoints; i++) {
-    points[i].Wx = weight_cauchy(points[i].rx / points[i].dX);
-    points[i].Wy = weight_cauchy(points[i].ry / points[i].dY);
-    
-    Sum_Wx += points[i].Wx;
-    Sum_Wy += points[i].Wy;
-  }
-  double WxThreshold = WEIGHT_THRESHOLD * Sum_Wx / (1.0 * Npoints);
-  double WyThreshold = WEIGHT_THRESHOLD * Sum_Wy / (1.0 * Npoints);
-
-  // set a mask (which can be used by the bootstrap resampling analysis)
-  for (i = 0; i < Npoints; i++) {
-    // keep if either is above threshold?
-    // drop if either is below threshold?
-    // points are marked as keep by default
-    if ((points[i].Wx < WxThreshold) || (points[i].Wy < WyThreshold)) {
-      points[i].mask = 1; // keep point if mask == 0
-    }
-  }
-
-  // this section calculates the formal error on the weighted fit using the covariance values
-  // NOTE EAM: in tests (fitpm.c), they seem to be too large by a factor of ~5.37
-  if (data->getError) {
-    double ax = 0.0, ay = 0.0;
-    double bx = 0.0, by = 0.0;
-
-    for (i = 0; i < Npoints; i++) {
-      ax += dpsi_cauchy(points[i].rx / points[i].dX);
-      ay += dpsi_cauchy(points[i].ry / points[i].dY);
-
-      bx += SQ(points[i].Wx);
-      by += SQ(points[i].Wy);
-    }
-    ax /= 1.0 * Npoints;  // mean(psi_dot(r))
-    ay /= 1.0 * Npoints; 
-    bx /= 1.0 * (Npoints - data->Nterms); // mean(psi^2(r)) * (N / (N-p))
-    by /= 1.0 * (Npoints - data->Nterms);
-  
-    double lambda_x = 1.0 + (data->Nterms / Npoints) * (1 - ax) / ax;
-    double lambda_y = 1.0 + (data->Nterms / Npoints) * (1 - ay) / ay;
-  
-    double sigma_robust_x = lambda_x * sqrt(bx) * sigma_hat * 2.385 / ax;
-    double sigma_robust_y = lambda_y * sqrt(by) * sigma_hat * 2.385 / ay;
-
-    // This is actually sigma^2, as that's the factor in the covariance (dumouchel 4.1)
-    double sigma_final_x  = MAX(SQ(sigma_robust_x), (2 * Npoints * SQ(sigma_robust_x) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-    double sigma_final_y  = MAX(SQ(sigma_robust_y), (2 * Npoints * SQ(sigma_robust_y) + SQ(data->Nterms * sigma_ols)) / (2 * Npoints + SQ(data->Nterms)));
-
-    fit[0].dRo = sqrt(data->Cov[0][0]);
-    fit[0].dDo = sqrt(data->Cov[1][1]);
-
-    fit[0].dRo *= sigma_final_x;
-    fit[0].dDo *= sigma_final_y;
-  }
-
-  // count unmasked points and (optionally) add up the chi square for the fit
-  double chisq = 0.0;
-  fit[0].Nfit = 0;
-  for (i = 0; i < Npoints; i++) {
-    if (points[i].mask) continue;
-    fit[0].Nfit ++;
-      
-    if (data->getChisq) {
-      double Xf = fit[0].Ro + fit[0].uR*points[i].T;
-      double Yf = fit[0].Do + fit[0].uD*points[i].T;
-      double wx = (fabs(points[i].dX) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dX);
-      double wy = (fabs(points[i].dY) < 0.0001) ? 1.0 : 1.0 / SQ(points[i].dY);
-      chisq += SQ(points[i].X - Xf) * wx;
-      chisq += SQ(points[i].Y - Yf) * wy;
-    }
-  }
-    
-  // the reduced chisq is divided by (Ndof = 2*Nfit - Nterms)
-  fit[0].chisq = chisq / (2.0*fit[0].Nfit - data->Nterms);
-
-  return (TRUE);
-}
-
-int weighted_LS_POS (FitAstromResult *fit, FitAstromData *data, FitAstromPoint *points, int Npoints, int VERBOSE) {
-
-  myAssert (data->Nterms == 2, "invalid fit arrays");
-
-  int i;
-  double wx, wy, Wx, Wy, Tx, Ty, Xs, Ys;
-
-  Wx = Wy = Tx = Ty = Xs = Ys = 0.0;
-
-  for (i = 0; i < Npoints; i++) {
-    wx = points[i].Wx;
-    wy = points[i].Wy;
-
-    Wx += wx;
-    Wy += wy;
-
-    Tx += points[i].T*wx;
-    Ty += points[i].T*wy;
-    
-    Xs += points[i].X*wx;
-    Ys += points[i].Y*wy;
-  }
-
-  // X^T W X
-  data->A[0][0] = Wx;
-  data->A[0][1] = 0.0;
-
-  data->A[1][0] = 0.0;
-  data->A[1][1] = Wy;
-
-  // X^T W Y
-  data->B[0][0] = Xs - fit->uR*Tx;
-  data->B[1][0] = Ys - fit->uD*Ty;
-
-  if (!dgaussjordan (data->A, data->B, 2, 1)) {
-    return FALSE;
-  }
-
-  fit->Ro = data->B[0][0];
-  fit->Do = data->B[1][0];
-  fit->p  = 0.0;
-
-  return TRUE;
-}
Index: trunk/Ohana/src/relastro/src/GetAstromError.c
===================================================================
--- trunk/Ohana/src/relastro/src/GetAstromError.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/GetAstromError.c	(revision 39926)
@@ -48,4 +48,13 @@
   if (isnan(code[0].astromErrSys)) return NAN;
 
+  if (measure[0].photcode == 1030) {
+    if (mode == ERROR_MODE_RA) {
+      dPobs = pow(10.0, (6.0 * measure[0].dXccd - 3.0));  // dXccd is a value in pixels
+    }
+    if (mode == ERROR_MODE_DEC) {
+      dPobs = pow(10.0, (6.0 * measure[0].dYccd - 3.0));  // dXccd is a value in pixels
+    }
+  }
+
   AS   	= code[0].astromErrScale;
   MS   	= code[0].astromErrMagScale;
@@ -69,7 +78,11 @@
   // to match the 2MASS / Tycho / ICRS reference frame.  As Nloop gets higher, the weight
   // needs to drop to allow the ps1 measurements to drive the solution
+  int isGAIA   = USE_GALAXY_MODEL && !isImage && (measure[0].photcode == 1030);
   int is2MASS  = USE_GALAXY_MODEL && !isImage && (measure[0].photcode >= 2011) && (measure[0].photcode <= 2013);
   int isTycho  = USE_GALAXY_MODEL && !isImage && (measure[0].photcode >= 2020) && (measure[0].photcode <= 2021);
+
+  int hasGAIA  = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_GAIA);
   int has2MASS = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_2MASS);
+  int hasTycho = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_TYCHO);
 
   // modest hack: if the object has 2MASS or Tycho, we set this internal bit and adjust the
@@ -79,6 +92,16 @@
     dPtotal = dPtotal / LoopWeight2MASS[Nloop];
   }
+  if (hasGAIA && LoopWeightGAIA && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightGAIA[Nloop];
+  }
+  if (hasTycho && LoopWeightTycho && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightTycho[Nloop];
+  }
+
   if (is2MASS && LoopWeight2MASS && (Nloop >= 0)) {
     dPtotal = dPtotal / LoopWeight2MASS[Nloop];
+  }
+  if (isGAIA && LoopWeightGAIA && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightGAIA[Nloop];
   }
   if (isTycho && LoopWeightTycho && (Nloop >= 0)) {
@@ -120,4 +143,13 @@
   // do not raise an exception, just send back the result
   if (isnan(code[0].astromErrSys)) return NAN;
+
+  if (measure[0].photcode == 1030) {
+    if (mode == ERROR_MODE_RA) {
+      dPobs = pow(10.0, (6.0 * measure[0].dXccd - 3.0));  // dXccd is a value in pixels
+    }
+    if (mode == ERROR_MODE_DEC) {
+      dPobs = pow(10.0, (6.0 * measure[0].dYccd - 3.0));  // dXccd is a value in pixels
+    }
+  }
 
   AS   	= code[0].astromErrScale;
@@ -143,7 +175,11 @@
   // to match the 2MASS / Tycho / ICRS reference frame.  As Nloop gets higher, the weight
   // needs to drop to allow the ps1 measurements to drive the solution
+  int isGAIA   = USE_GALAXY_MODEL && !isImage && (measure[0].photcode == 1030);
   int is2MASS  = USE_GALAXY_MODEL && !isImage && (measure[0].photcode >= 2011) && (measure[0].photcode <= 2013);
   int isTycho  = USE_GALAXY_MODEL && !isImage && (measure[0].photcode >= 2020) && (measure[0].photcode <= 2021);
+
+  int hasGAIA  = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_GAIA);
   int has2MASS = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_2MASS);
+  int hasTycho = USE_GALAXY_MODEL &&  isImage && (measure[0].dbFlags & ID_MEAS_OBJECT_HAS_TYCHO);
 
   // modest hack: if the object has 2MASS or Tycho, we set this internal bit and adjust the
@@ -153,6 +189,16 @@
     dPtotal = dPtotal / LoopWeight2MASS[Nloop];
   }
+  if (hasGAIA && LoopWeightGAIA && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightGAIA[Nloop];
+  }
+  if (hasTycho && LoopWeightTycho && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightTycho[Nloop];
+  }
+
   if (is2MASS && LoopWeight2MASS) {
     dPtotal = dPtotal / LoopWeight2MASS[Nloop];
+  }
+  if (isGAIA && LoopWeightGAIA && (Nloop >= 0)) {
+    dPtotal = dPtotal / LoopWeightGAIA[Nloop];
   }
   if (isTycho && LoopWeightTycho) {
Index: trunk/Ohana/src/relastro/src/ImageOps.c
===================================================================
--- trunk/Ohana/src/relastro/src/ImageOps.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/ImageOps.c	(revision 39926)
@@ -6,4 +6,5 @@
 static Image        *image;   // list of available images
 static off_t        Nimage;   // number of available images
+static int         isImageSubset;
 
 // if we read only a subset of the rows from the Image FITS, LineNumber tells us to which row
@@ -78,8 +79,9 @@
 }
 
-void initImages (Image *input, off_t *line_number, off_t N) {
+void initImages (Image *input, off_t *line_number, off_t N, int isSubset) {
 
   off_t i;
 
+  isImageSubset = isSubset;
   image = input;
   LineNumber = line_number;
@@ -136,5 +138,5 @@
   // we call gfits_db_free as well as this function.  sometimes those point at the same
   // memory location, in which case we should only do the free once.
-  if ((void *) dbImagePtr != (void *) image) free (image);
+  if (((void *) dbImagePtr != (void *) image) && isImageSubset) free (image);
   free_astrom_table();
 }
@@ -793,6 +795,13 @@
     ref[i].D = catalog[c].average[n].D;
     
+    int XVERB = FALSE;
+    XVERB |= (catalog[c].average[n].objID == OBJ_ID_SRC) && (catalog[c].average[n].catID == CAT_ID_SRC);
+    XVERB |= (catalog[c].average[n].objID == OBJ_ID_DST) && (catalog[c].average[n].catID == CAT_ID_DST);
+    if (XVERB) {
+      fprintf (stderr, "found test object\n");
+    }
+
     // if we are applying the galaxy model, move the reference position...
-    if (USE_GALAXY_MODEL) {
+    if (APPLY_PROPER_MOTION) {
       // apply proper-motion from average position to measure epoch:
       float dTime = (measure[0].t - catalog[c].average[n].Tmean) / (86400*365.25) ; // time relative to Tmean in years
@@ -934,371 +943,2 @@
 }
 
-# if (0) 
-/** lifted from relphot/StarOps.clean_measures */
-void FlagOutliers2D(Catalog *catalog);
-
-// operates on Full values (not tiny)
-void FlagOutliers (Catalog *catalog) {
-
-  // XXX FlagOutliers is now just using FlagOutliers2D
-  FlagOutliers2D(catalog);
-  return;
-
-  int Ndel, Nave;
-  off_t i, j, k, m, N, Nmax, TOOFEW, Nsecfilt;
-  double Ns, theta, x, y;
-  double *R, *D, *dR, *dD;
-  StatType statsR, statsD;
-
-  Nsecfilt = GetPhotcodeNsecfilt();
-  assert(catalog[0].Nsecfilt == Nsecfilt);
-
-  if (VERBOSE2) fprintf (stderr, "marking poor measures\n");
-  Nmax = 0;
-  for (i = 0; i < catalog[0].Naverage; i++) {
-    Nmax = MAX (Nmax, catalog[0].average[i].Nmeasure);
-  }
-
-  ALLOCATE (R, double, Nmax);
-  ALLOCATE (D, double, Nmax);
-  ALLOCATE (dR, double, Nmax);
-  ALLOCATE (dD, double, Nmax);
-
-  /* it makes no sense to mark 3-sigma outliers with <5 measurements */
-  TOOFEW = MAX (5, SRC_MEAS_TOOFEW);
-
-  Ns = CLIP_THRESH;
-  Ndel = Nave = 0;
-      
-  /* loop over each object in the catalog */
-  for (j = 0; j < catalog[0].Naverage; j++) {
-    
-    // pointer to this set of measurements
-    m = catalog[0].average[j].measureOffset;
-    Measure *measure = &catalog[0].measure[m];
-
-    /* accumulate list of valid measurements */
-    N = 0;
-    for (k = 0; k < catalog[0].average[j].Nmeasure; k++) {
-      // skip measurements based on user selected criteria
-      if (!MeasFilterTest(&measure[k], FALSE)) continue;
-      R[N] = measure[k].R;
-      D[N] = measure[k].D;
-      dR[N] = GetAstromError (&measure[k], ERROR_MODE_RA);
-      dD[N] = GetAstromError (&measure[k], ERROR_MODE_DEC);
-      if (isnan(R[N]) || isnan(D[N])) continue;
-      N++;
-    }
-    if (N <= TOOFEW) continue;
-    
-    /* 3-sigma clip based on stats of inner 50% */
-    initstats ("MEAN");
-    liststats (R, dR, N, &statsR);
-    liststats (D, dD, N, &statsD);
-    
-    statsR.sigma = MAX (MIN_ERROR, statsR.sigma);
-    statsD.sigma = MAX (MIN_ERROR, statsD.sigma);
-    
-    /* compare per-object distance to this standard deviation, and flag outliers*/
-    N = 0;
-    for (k = 0; k < catalog[0].average[j].Nmeasure; k++) {
-      // reset flag on each invocation
-      measure[k].dbFlags &= ~ID_MEAS_POOR_ASTROM;
-
-      // skip measurements based on user selected criteria
-      if (!MeasFilterTest(&measure[k], FALSE)) continue;
-      
-      x = measure[k].R - statsR.median;
-      y = measure[k].D - statsD.median;
-      theta = atan2(y,x);
-      if ((x*x + y*y) > (SQR(statsR.sigma * Ns * cos(theta)) + 
-			 SQR(statsD.sigma * Ns * sin(theta)))) {   
-	measure[k].dbFlags |= ID_MEAS_POOR_ASTROM;
-	Ndel++;
-      }
-      N++;
-      Nave ++;
-    }
-
-    // examine results
-    // relastroVisualPlotOutliers(catalog, catalog[0].average[j].measureOffset, catalog[0].average[j].Nmeasure, statsR, statsD, Ns);
-  }
-  
-  if (VERBOSE) fprintf (stderr, "%d measures marked poor, %d total\n", Ndel, Nave);
-  free (R);
-  free (dR);
-  free (D);
-  free (dD); 
-}
-
-
-/** an alternative outlier rejection scheme */
-void FlagOutliers2D (Catalog *catalog) {
-
-  int Ndel, Nave;
-  off_t i, j, k, m, N, Nmax, TOOFEW, Nsecfilt;
-  double *index;
-  double Ns, theta, x, y;
-  double *R, *D, *dR, *dD, *d2;
-  StatType statsR, statsD;
-
-  // XXX we are not going to use this for now
-  return;
-
-  Nsecfilt = GetPhotcodeNsecfilt();
-  assert(catalog[0].Nsecfilt == Nsecfilt);
-
-  if (VERBOSE2) fprintf (stderr, "marking poor measures\n");
-  Nmax = 0;
-  for (i = 0; i < catalog[0].Naverage; i++) {
-    Nmax = MAX (Nmax, catalog[0].average[i].Nmeasure);
-  }
-
-  ALLOCATE (R, double, Nmax);
-  ALLOCATE (D, double, Nmax);
-  ALLOCATE (dR, double, Nmax);
-  ALLOCATE (dD, double, Nmax);
-  ALLOCATE (d2, double, Nmax);
-  ALLOCATE (index, double, Nmax);
-
-  /* it makes no sense to mark 3-sigma outliers with <5 measurements */
-  TOOFEW = MAX (5, SRC_MEAS_TOOFEW);
-
-  Ns = CLIP_THRESH;
-  Ndel = Nave = 0;
-      
-  /* loop over each object in the catalog */
-  for (j = 0; j < catalog[0].Naverage; j++) {
-    
-    // pointer to this set of measurements
-    m = catalog[0].average[j].measureOffset;
-    Measure *measure = &catalog[0].measure[m];
-
-    /* accumulate list of valid measurements */
-    N = 0;
-    for (k = 0; k < catalog[0].average[j].Nmeasure; k++) {
-
-      // reset flag on each invocation
-      measure[k].dbFlags &= ~ID_MEAS_POOR_ASTROM;
-      
-      // skip measurements based on user selected criteria
-      if (!MeasFilterTest(&measure[k], FALSE)) continue;
-      R[N] = measure[k].R;
-      D[N] = measure[k].D;
-      dR[N] = GetAstromError(&measure[k], ERROR_MODE_RA);
-      dD[N] = GetAstromError(&measure[k], ERROR_MODE_DEC);
-      if (isnan(R[N]) || isnan(D[N])) continue;
-      N++;
-    }
-    if (N <= TOOFEW) continue;
-    
-    /* calculate mean of all points*/
-    initstats ("MEAN");
-    liststats (R, dR, N, &statsR);
-    liststats (D, dD, N, &statsD);
-    statsR.sigma = MAX (MIN_ERROR, statsR.sigma);
-    statsD.sigma = MAX (MIN_ERROR, statsD.sigma);
-    
-    /* calculate deviations of all points*/
-    N = 0;
-    for (k = 0; k < catalog[0].average[j].Nmeasure; k++) {
-      // skip bad measurements
-      if (!MeasFilterTest(&measure[k], FALSE)) continue;  
-      x = measure[k].R - statsR.median;
-      y = measure[k].D - statsD.median;
-      theta = atan2(y,x);
-      d2[N] = (x*x + y*y) / (SQR(statsR.sigma * Ns * cos(theta)) + 
-			     SQR(statsD.sigma * Ns * sin(theta)));      
-      index[N] = k;
-      N++;
-    }
-    
-    // sort d2
-    dsortpair(d2, index, N);
-    N = (N/2 > (N-1)) ? N/2 : N-1;
-
-    // recalculate image center, sigma based on closest 50% of points
-    for (k = 0;  k < N; k++) {
-      off_t ind = (off_t) index[k];
-      R[k] = measure[ind].R;
-      D[k] = measure[ind].D;
-      dR[k] = GetAstromError(&measure[ind], ERROR_MODE_RA);
-      dD[k] = GetAstromError(&measure[ind], ERROR_MODE_DEC);
-    }
-    liststats (R, dR, N, &statsR);
-    liststats (D, dD, N, &statsD);
-    statsR.sigma = MAX (MIN_ERROR, statsR.sigma);
-    statsD.sigma = MAX (MIN_ERROR, statsD.sigma);
-    
-    // use these new statistics to flag outliers 
-    N = 0;
-    for (k = 0; k < catalog[0].average[j].Nmeasure; k++) {
-      //skip bad measurements
-      if (!MeasFilterTest(&measure[k], FALSE)) continue;  
-      x = measure[k].R - statsR.median;
-      y = measure[k].D - statsD.median;
-      theta = atan2(y,x);
-      d2[N] = (x*x + y*y) / (SQR(statsR.sigma * Ns * cos(theta)) + 
-			     SQR(statsD.sigma * Ns * sin(theta)));      
-      if ((d2[N]) > 1) {
-	measure[k].dbFlags |= ID_MEAS_POOR_ASTROM;
-	Ndel ++;
-      }
-      N++;
-      Nave++;
-    }  // done rejecting outliers
-
-    // examine results
-    // relastroVisualPlotOutliers(catalog, catalog[0].average[j].measureOffset, catalog[0].average[j].Nmeasure, statsR, statsD, Ns);
-    
-  } // done looping over objects
-  
-  if (VERBOSE) fprintf (stderr, "%d measures marked poor, %d total\n", Ndel, Nave);
-  free (R);
-  free (dR);
-  free (D);
-  free (dD); 
-  free (d2);
-  free (index);
-}
-
-/** Determine whether a measurement should be included in the analysis, based on supplied filter criteria */ 
-// we only optionally apply the sigma limit: for object averages, this should not be used
-int MeasFilterTestTiny(MeasureTiny *measure, int applySigmaLim) {
-  int found, k;
-  long mask;
-  PhotCode *code;
-  float mag;
-
-  if (!finite(measure[0].R) || !finite(measure[0].D)) return FALSE;
-  if (!finite(measure[0].M)) return FALSE; //XXX is this necessary for all relastro tasks?
-  if (!finite(measure[0].dM)) return FALSE; //XXX is this necessary for all relastro tasks?
-  
-  if ((MinBadQF > 0.0) && (isGPC1chip(measure[0].photcode) || isGPC1stack(measure[0].photcode))) {
-    if (!isfinite(measure[0].psfQF)) { return FALSE; };
-    if (measure[0].psfQF < MinBadQF) { return FALSE; };
-  }
-
-  /* select measurements by photcode, or equiv photcode, if specified */
-  if (NphotcodesKeep > 0) {
-    found = FALSE;
-    for (k = 0; (k < NphotcodesKeep) && !found; k++) {
-      if (photcodesKeep[k][0].code == measure[0].photcode) found = TRUE;
-      if (photcodesKeep[k][0].code == GetPhotcodeEquivCodebyCode(measure[0].photcode)) found = TRUE;
-    }
-    if (!found) return FALSE;
-  }
-  
-  if (NphotcodesSkip > 0) {
-    found = FALSE;
-    for (k = 0; (k < NphotcodesSkip) && !found; k++) {
-      if (photcodesSkip[k][0].code == measure[0].photcode) found = TRUE;
-      if (photcodesSkip[k][0].code == GetPhotcodeEquivCodebyCode(measure[0].photcode)) found = TRUE;
-    }
-    if (found) return FALSE;
-  }  
-  
-  /* select measurements by time */
-  if (TimeSelect) {
-    if (measure[0].t < TSTART) return FALSE;
-    if (measure[0].t > TSTOP) return FALSE;
-  }
-  
-  /* select measurements by quality */
-  if (PhotFlagSelect) {
-    if (PhotFlagBad) {
-      mask = PhotFlagBad;
-    } else {
-      code = GetPhotcodebyCode (measure[0].photcode);
-      if (!code) return FALSE;
-      mask = code[0].astromBadMask;
-    }
-    if (mask & measure[0].photFlags) return FALSE;
-  }
-
-  /* select measurements by measurement error */
-  // this is a bit convoluted: applySigmaLim is only TRUE when this function is
-  // called by bcatalog.  for UpdateObjects, it is FALSE
-  if (applySigmaLim && (SIGMA_LIM > 0) && (measure[0].dM > SIGMA_LIM)) {
-    return FALSE;
-  }
-  
-  /* select measurements by mag limit */
-  if (ImagSelect) {
-    mag = PhotInstTiny (measure, MAG_CLASS_PSF);
-    if (mag < ImagMin || mag > ImagMax) return FALSE;
-  }
-  
-  return TRUE;
-}
-
-# define SUPER_VERBOSE 0
-
-/** Determine whether a measurement should be included in the analysis, based on supplied filter criteria */ 
-// we only optionally apply the sigma limit: for object averages, this should not be used (should it?)
-int MeasFilterTest(Measure *measure, int applySigmaLim) {
-  int found, k;
-  long mask;
-  PhotCode *code;
-  float mag;
-
-  if (!finite(measure[0].R) || !finite(measure[0].D)) { if (SUPER_VERBOSE) fprintf (stderr, "filter 1\n"); return FALSE; };
-  if (!finite(measure[0].M)) { if (SUPER_VERBOSE) fprintf (stderr, "filter 2\n"); return FALSE; }; //XXX is this necessary for all relastro tasks?
-  if (!finite(measure[0].dM)) { if (SUPER_VERBOSE) fprintf (stderr, "filter 3\n"); return FALSE; }; //XXX is this necessary for all relastro tasks?
-  
-  /* select measurements by photcode, or equiv photcode, if specified */
-  if (NphotcodesKeep > 0) {
-    found = FALSE;
-    for (k = 0; (k < NphotcodesKeep) && !found; k++) {
-      if (photcodesKeep[k][0].code == measure[0].photcode) found = TRUE;
-      if (photcodesKeep[k][0].code == GetPhotcodeEquivCodebyCode(measure[0].photcode)) found = TRUE;
-    }
-    if (!found) { if (SUPER_VERBOSE) fprintf (stderr, "filter 4\n"); return FALSE; };
-  }
-  
-  if (NphotcodesSkip > 0) {
-    found = FALSE;
-    for (k = 0; (k < NphotcodesSkip) && !found; k++) {
-      if (photcodesSkip[k][0].code == measure[0].photcode) found = TRUE;
-      if (photcodesSkip[k][0].code == GetPhotcodeEquivCodebyCode(measure[0].photcode)) found = TRUE;
-    }
-    if (found) { if (SUPER_VERBOSE) fprintf (stderr, "filter 5\n"); return FALSE; };
-  }  
-  
-  if ((MinBadQF > 0.0) && isGPC1chip(measure[0].photcode)) {
-    if (!isfinite(measure[0].psfQF)) { if (SUPER_VERBOSE) fprintf (stderr, "filter 6\n"); return FALSE; };
-    if (measure[0].psfQF < MinBadQF) { if (SUPER_VERBOSE) fprintf (stderr, "filter 7\n"); return FALSE; };
-  }
-
-  /* select measurements by time */
-  if (TimeSelect) {
-    if (measure[0].t < TSTART) { if (SUPER_VERBOSE) fprintf (stderr, "filter 8\n"); return FALSE; };
-    if (measure[0].t > TSTOP) { if (SUPER_VERBOSE) fprintf (stderr, "filter 9\n"); return FALSE; };
-  }
-  
-  /* select measurements by quality */
-  if (PhotFlagSelect) {
-    if (PhotFlagBad) {
-      mask = PhotFlagBad;
-    } else {
-      code = GetPhotcodebyCode (measure[0].photcode);
-      if (!code) { if (SUPER_VERBOSE) fprintf (stderr, "filter 10\n"); return FALSE; };
-      mask = code[0].astromBadMask;
-    }
-    if (mask & measure[0].photFlags) { if (SUPER_VERBOSE) fprintf (stderr, "filter 11\n"); return FALSE; };
-  }
-
-  /* select measurements by measurement error */
-  if (applySigmaLim && (SIGMA_LIM > 0) && (measure[0].dM > SIGMA_LIM)) {
-    { if (SUPER_VERBOSE) fprintf (stderr, "filter 12\n"); return FALSE; };
-  }
-  
-  /* select measurements by mag limit */
-  if (ImagSelect) {
-    mag = PhotInst (measure, MAG_CLASS_PSF);
-    if (mag < ImagMin || mag > ImagMax) { if (SUPER_VERBOSE) fprintf (stderr, "filter 13\n"); return FALSE; };
-  }
-  
-  return TRUE;
-}
-# endif
Index: trunk/Ohana/src/relastro/src/StarMaps.c
===================================================================
--- trunk/Ohana/src/relastro/src/StarMaps.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/StarMaps.c	(revision 39926)
@@ -166,4 +166,19 @@
   dLmax = dMmax = 0.0;
 
+  float plateScale;
+  if (images[N].coords.mosaic) {
+    // NOTE: for the full pixel to sky plate scale, use this:
+    // float plateScaleX = 3600.0*images[N].coords.mosaic->cdelt1*images[N].coords.cdelt1;
+    // float plateScaleY = 3600.0*images[N].coords.mosaic->cdelt2*images[N].coords.cdelt2;
+
+    // since we are compare L,M values, just need to compensate for focal plate to sky:
+    float plateScaleX = 3600.0*fabs(images[N].coords.mosaic->cdelt1);
+    float plateScaleY = 3600.0*fabs(images[N].coords.mosaic->cdelt2);
+    plateScale = 0.5*(plateScaleX + plateScaleY);
+  } else {
+    // since we are compare L,M values, just need to compensate for arcsec vs degrees:
+    plateScale = 3600.0;
+  }
+
   for (i = 0; i < starmap[N].Npoints; i++) {
 
@@ -171,6 +186,6 @@
     XY_to_LM (&L, &M, starmap[N].points[i].X, starmap[N].points[i].Y, &images[N].coords);
 
-    starmap[N].points[i].dL = starmap[N].points[i].L - L;
-    starmap[N].points[i].dM = starmap[N].points[i].M - M;
+    starmap[N].points[i].dL = plateScale*(starmap[N].points[i].L - L);
+    starmap[N].points[i].dM = plateScale*(starmap[N].points[i].M - M);
 
     dLmax = MAX(fabs(starmap[N].points[i].dL), dLmax);
Index: trunk/Ohana/src/relastro/src/UpdateChips.c
===================================================================
--- trunk/Ohana/src/relastro/src/UpdateChips.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/UpdateChips.c	(revision 39926)
@@ -42,4 +42,8 @@
   AstromErrorSetLoop (Nloop, TRUE);
 
+  // if ChipMapLoop or ChipOrderLoop is set use that to define the value of CHIPMAP and/or CHIPORDER this loop
+  if (ChipMapLoop) { CHIPMAP = ChipMapLoop[Nloop]; }
+  if (ChipOrderLoop) { CHIPORDER = ChipOrderLoop[Nloop]; }
+  
   if (NTHREADS) {
     UpdateChips_threaded (catalog, Ncatalog);
@@ -60,9 +64,18 @@
   for (i = 0; i < Nimage; i++) {
 
-    VERBOSE_IMAGE = !strcmp(image[i].name, "o5745g0516o.356887.cm.982631.smf[XY54]");
+    VERBOSE = FALSE;
+    VERBOSE_IMAGE |= !strcmp(image[i].name, "o5745g0516o.356887.cm.982631.smf[XY45]");
+    VERBOSE_IMAGE |= !strcmp(image[i].name, "o5745g0526o.356899.cm.982643.smf[XY45]");
+    VERBOSE_IMAGE |= !strcmp(image[i].name, "o5748g0436o.358811.cm.982690.smf[XY34]");
 
     // XXX looks like everything below is thread safe : we can unroll this into a set of
     // helper functions that grab the next available chip....
 
+    // allow certain cameras to stay static
+    if (SKIP_PS1_CHIP  && isGPC1chip (image[i].photcode)) { Nskip ++;  mode[i] = 0; continue; }
+    if (SKIP_PS1_STACK && isGPC1stack(image[i].photcode)) { Nskip ++;  mode[i] = 0; continue; }
+    if (SKIP_HSC       && isHSCchip  (image[i].photcode)) { Nskip ++;  mode[i] = 0; continue; }
+    if (SKIP_CFH       && isCFHchip  (image[i].photcode)) { Nskip ++;  mode[i] = 0; continue; }
+    
     /* skip all except WRP images */
     if (strcmp(&image[i].coords.ctype[4], "-WRP")) {
@@ -160,5 +173,5 @@
     setImageRaw (catalog, Ncatalog, i, raw, Nraw, MODE_MOSAIC);
     if (USE_GALAXY_MODEL) {
-      // XXX DEPRECATE?
+      // the image calibration was calculated using a galaxy motion model
       image[i].flags |= ID_IMAGE_ASTROM_GMM;
     }
@@ -281,4 +294,10 @@
     }
 
+    // allow certain cameras to stay static
+    if (SKIP_PS1_CHIP  && isGPC1chip (image[i].photcode)) { threadinfo->Nskip ++;  threadinfo->mode[i] = 0; continue; }
+    if (SKIP_PS1_STACK && isGPC1stack(image[i].photcode)) { threadinfo->Nskip ++;  threadinfo->mode[i] = 0; continue; }
+    if (SKIP_HSC       && isHSCchip  (image[i].photcode)) { threadinfo->Nskip ++;  threadinfo->mode[i] = 0; continue; }
+    if (SKIP_CFH       && isCFHchip  (image[i].photcode)) { threadinfo->Nskip ++;  threadinfo->mode[i] = 0; continue; }
+    
     /* skip all except WRP images */
     if (strcmp(&image[i].coords.ctype[4], "-WRP")) {
Index: trunk/Ohana/src/relastro/src/UpdateMeasures.c
===================================================================
--- trunk/Ohana/src/relastro/src/UpdateMeasures.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/UpdateMeasures.c	(revision 39926)
@@ -115,5 +115,32 @@
 
       // only modify the chip coordinates
-      if (isGPC1chip (measureT->photcode)) {
+      if (UPDATE_PS1_STACK_MEASURE && isGPC1stack (measureT->photcode)) {
+	measureT->R = R;
+	measureT->D = D;
+	if (measureB) {
+	  measureB->R = R;
+	  measureB->D = D;
+	}
+      }
+      // only modify the chip coordinates
+      if (UPDATE_PS1_CHIP_MEASURE && isGPC1chip (measureT->photcode)) {
+	measureT->R = R;
+	measureT->D = D;
+	if (measureB) {
+	  measureB->R = R;
+	  measureB->D = D;
+	}
+      }
+      // only modify the chip coordinates
+      if (UPDATE_HSC_MEASURE && isGPC1chip (measureT->photcode)) {
+	measureT->R = R;
+	measureT->D = D;
+	if (measureB) {
+	  measureB->R = R;
+	  measureB->D = D;
+	}
+      }
+      // only modify the chip coordinates
+      if (UPDATE_CFH_MEASURE && isGPC1chip (measureT->photcode)) {
 	measureT->R = R;
 	measureT->D = D;
Index: trunk/Ohana/src/relastro/src/UpdateObjectOffsets.c
===================================================================
--- trunk/Ohana/src/relastro/src/UpdateObjectOffsets.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/UpdateObjectOffsets.c	(revision 39926)
@@ -167,10 +167,14 @@
     strextend (&command, "relastro_client -update-offsets");
     strextend (&command, "-hostID %d", group->hosts[i][0].hostID);
+    strextend (&command, "-hostdir %s", group->hosts[i][0].pathname);
+
     strextend (&command, "-D CATDIR %s", CATDIR);
-    strextend (&command, "-hostdir %s", group->hosts[i][0].pathname);
     strextend (&command, "-region %f %f %f %f", UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax);
     strextend (&command, "-statmode %s", STATMODE);
     strextend (&command, "-minerror %f", MIN_ERROR);
 
+    strextend (&command, "-D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
+    strextend (&command, "-D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
+
     if (FIT_MODE == FIT_PM_ONLY)  	 strextend (&command, "-pm");
     if (FIT_MODE == FIT_PAR_ONLY) 	 strextend (&command, "-par");
@@ -180,21 +184,11 @@
     if (VERBOSE2)      strextend (&command, "-vv");
     if (RESET)         strextend (&command, "-reset");
-    if (UPDATE)        strextend (&command, "-update");
-
-    if (RESET_BAD_IMAGES) strextend (&command, "-reset-bad-images");
 
     if (ImagSelect)    strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
     if (MaxDensityUse) strextend (&command, "-max-density %f", MaxDensityValue);
-    
-    if (USE_BASIC_CHECK) strextend (&command, "-basic-image-search");
     if (FlagOutlier)     strextend (&command, "-clip %d", CLIP_THRESH);
     if (ExcludeBogus)    strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
     
-    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
     if (USE_FIXED_PIXCOORDS) strextend (&command, "-D USE_FIXED_PIXCOORDS 1"); 
-
-    if (REPAIR_STACKS)          strextend (&command, "-repair-stacks-on-update");
-    if (CHECK_MEASURE_TO_IMAGE) strextend (&command, "-check-measures");
-
     if (PHOTCODE_KEEP_LIST) strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST);
     if (PHOTCODE_SKIP_LIST) strextend (&command, "-photcode %s", PHOTCODE_SKIP_LIST);
@@ -204,6 +198,4 @@
     // XXX note that the above pass in the flag as decimal -- also note that args.c cannot handle 0xHEX values
 
-    if (N_BOOTSTRAP_SAMPLES > 1) strextend (&command, "-bootstrap-samples %d", N_BOOTSTRAP_SAMPLES); 
-
     if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
       strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
@@ -213,6 +205,20 @@
     }
 
+    if (REPAIR_STACKS)          strextend (&command, "-repair-stacks-on-update");
+    if (CHECK_MEASURE_TO_IMAGE) strextend (&command, "-check-measures");
+
+    if (UPDATE_PS1_STACK_MEASURE) strextend (&command, "-update-ps1-stack");
+    if (UPDATE_PS1_CHIP_MEASURE) strextend (&command, "-update-ps1-chip");
+    if (UPDATE_HSC_MEASURE)    	 strextend (&command, "-update-hsc");
+    if (UPDATE_CFH_MEASURE)    	 strextend (&command, "-update-cfh");
+
+    if (UPDATE)        strextend (&command, "-update");
+    if (RESET_BAD_IMAGES) strextend (&command, "-reset-bad-images");
+    if (USE_BASIC_CHECK) strextend (&command, "-basic-image-search");
+    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
+
     if (MinBadQF > 0.0)        strextend (&command, "-min-bad-psfqf %f", MinBadQF); 
     if (MaxMeanOffset != 10.0) strextend (&command, "-max-mean-offset  %f", MaxMeanOffset);
+    if (N_BOOTSTRAP_SAMPLES > 1) strextend (&command, "-bootstrap-samples %d", N_BOOTSTRAP_SAMPLES); 
 
     if (TimeSelect) { 
@@ -300,10 +306,14 @@
     strextend (&command, "relastro_client -update-offsets");
     strextend (&command, "-hostID %d", table->hosts[i].hostID);
+    strextend (&command, "-hostdir %s", table->hosts[i].pathname);
+
     strextend (&command, "-D CATDIR %s", CATDIR);
-    strextend (&command, "-hostdir %s", table->hosts[i].pathname);
     strextend (&command, "-region %f %f %f %f", UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax);
     strextend (&command, "-statmode %s", STATMODE);
     strextend (&command, "-minerror %f", MIN_ERROR);
 
+    strextend (&command, "-D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
+    strextend (&command, "-D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
+
     if (FIT_MODE == FIT_PM_ONLY)  	 strextend (&command, "-pm");
     if (FIT_MODE == FIT_PAR_ONLY) 	 strextend (&command, "-par");
@@ -313,21 +323,11 @@
     if (VERBOSE2)      strextend (&command, "-vv");
     if (RESET)         strextend (&command, "-reset");
-    if (UPDATE)        strextend (&command, "-update");
-
-    if (RESET_BAD_IMAGES) strextend (&command, "-reset-bad-images");
 
     if (ImagSelect)    strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
     if (MaxDensityUse) strextend (&command, "-max-density %f", MaxDensityValue);
-    
-    if (USE_BASIC_CHECK) strextend (&command, "-basic-image-search");
     if (FlagOutlier)     strextend (&command, "-clip %d", CLIP_THRESH);
     if (ExcludeBogus)    strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
     
-    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
     if (USE_FIXED_PIXCOORDS) strextend (&command, "-D USE_FIXED_PIXCOORDS 1"); 
-
-    if (REPAIR_STACKS)          strextend (&command, "-repair-stacks-on-update");
-    if (CHECK_MEASURE_TO_IMAGE) strextend (&command, "-check-measures");
-
     if (PHOTCODE_KEEP_LIST) strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST);
     if (PHOTCODE_SKIP_LIST) strextend (&command, "-photcode %s", PHOTCODE_SKIP_LIST);
@@ -337,6 +337,4 @@
     // XXX note that the above pass in the flag as decimal -- also note that args.c cannot handle 0xHEX values
 
-    if (N_BOOTSTRAP_SAMPLES > 1) strextend (&command, "-bootstrap-samples %d", N_BOOTSTRAP_SAMPLES); 
-
     if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
       strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
@@ -345,4 +343,19 @@
       strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
     }
+
+    if (REPAIR_STACKS)          strextend (&command, "-repair-stacks-on-update");
+    if (CHECK_MEASURE_TO_IMAGE) strextend (&command, "-check-measures");
+
+    if (UPDATE_PS1_STACK_MEASURE) strextend (&command, "-update-ps1-stack");
+    if (UPDATE_PS1_CHIP_MEASURE) strextend (&command, "-update-ps1-chip");
+    if (UPDATE_HSC_MEASURE)    	 strextend (&command, "-update-hsc");
+    if (UPDATE_CFH_MEASURE)    	 strextend (&command, "-update-cfh");
+
+    if (UPDATE)        strextend (&command, "-update");
+    if (RESET_BAD_IMAGES) strextend (&command, "-reset-bad-images");
+    if (USE_BASIC_CHECK) strextend (&command, "-basic-image-search");
+    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
+
+    if (N_BOOTSTRAP_SAMPLES > 1) strextend (&command, "-bootstrap-samples %d", N_BOOTSTRAP_SAMPLES); 
 
     if (MinBadQF > 0.0)        strextend (&command, "-min-bad-psfqf %f", MinBadQF); 
Index: trunk/Ohana/src/relastro/src/UpdateObjects.c
===================================================================
--- trunk/Ohana/src/relastro/src/UpdateObjects.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/UpdateObjects.c	(revision 39926)
@@ -5,13 +5,15 @@
 # define PAR_MIN_NPTS 7
 # define PAR_MIN_NPTS_BOOT 6
-# define PM_MIN_NPTS 4
-# define PM_MIN_NPTS_BOOT 3
-# define POS_MIN_NPTS 3
-# define POS_MIN_NPTS_BOOT 2
+# define PM_MIN_NPTS 5
+# define PM_MIN_NPTS_BOOT 4
+# define POS_MIN_NPTS 4
+# define POS_MIN_NPTS_BOOT 4
 
 typedef enum {
-  SELECT_MEAS_HAS_DATA  = 1,
-  SELECT_MEAS_HAS_STACK = 2,
-  SELECT_MEAS_HAS_2MASS = 4,
+  SELECT_MEAS_HAS_DATA  = 0x01,
+  SELECT_MEAS_HAS_STACK = 0x02,
+  SELECT_MEAS_HAS_2MASS = 0x04,
+  SELECT_MEAS_HAS_GAIA  = 0x08,
+  SELECT_MEAS_HAS_TYCHO = 0x10,
 } SelectMeasureStatus;
 
@@ -181,34 +183,39 @@
     if (Trange < PM_DT_MIN) {
       // not enough baseline for proper motion, only set mean position
-      mode = FIT_AVERAGE;
       goto justPosition;
     }
     if (parRange < PAR_FACTOR_MIN) {
       // not enough parallax factor range, skip parallax
-      mode = FIT_PM_ONLY;
       goto skipParallax;
     }
     if (fitStats->Npoints < PAR_MIN_NPTS) {
       // not enough data, skip parallax
-      mode = FIT_PM_ONLY;
       goto skipParallax;
     }
 
     // we are going to use the IRLS analysis to calculate the mean solution and the masking
-    // then run N_BOOTSTRAP_SAMPLES to measure the errors
-    fitStats->fitdataPar->getError = !N_BOOTSTRAP_SAMPLES;
-    if (!FitPMandPar_IRLS (&fitPar, fitStats->fitdataPar, fitStats->points, fitStats->Npoints)) {
-      mode = FIT_PM_ONLY;
-      goto skipParallax;
-    }
-
-    if (N_BOOTSTRAP_SAMPLES) {
+    // then run N_BOOTSTRAP_SAMPLES to measure the errors.  We first measure the OLS error,
+    // and choose the max of the OLS and bootstrap errors
+    fitStats->fitdataPar->getError = TRUE;
+    if (USE_IRLS) {
+      if (!FitPMandPar_IRLS (&fitPar, fitStats->fitdataPar, fitStats->points, fitStats->Npoints)) {
+	goto skipParallax;
+      }
+    } else {
+      if (!FitPMandPar_Basic (&fitPar, fitStats->fitdataPar, fitStats->points, fitStats->Npoints)) {
+	goto skipParallax;
+      }
+    }
+
+    // in the fits above, we have saved the formal error for the unmasked points.  
+    // if we do not have enough points for bootstrap, we will keep those errors
+    if (N_BOOTSTRAP_SAMPLES && (fitPar.Nfit >= PAR_MIN_NPTS_BOOT)) {
       fitStats->Nfit = 0;
       int Nnomask = BootstrapSaveUnmasked (fitStats->nomask, fitStats->points, fitStats->Npoints);
-      if (Nnomask < PAR_MIN_NPTS_BOOT) {
-	// if we do not have enough points to assess parallax error, we cannot do the bootstrap analysis.
-	mode = FIT_PM_ONLY;
-	goto skipParallax;
-      }
+
+      // if we do not have enough points to assess parallax error, skip the bootstrap analysis.
+      // (I think the test above means we never do this skip)
+      if (Nnomask < PAR_MIN_NPTS_BOOT) goto skipParallaxBootstrap;
+
       for (k = 0; k < fitStats->NfitAlloc; k++) {
 	BootstrapResample (fitStats->sample, fitStats->nomask, Nnomask);
@@ -216,5 +223,8 @@
 	fitStats->Nfit ++;
       }
-      // these calls set the ERRORS on the fit parameters, not the fit values (set in IRLS above)
+
+      // These calls set the ERRORS on the fit parameters, not the fit values (set in IRLS above)
+      // this call expects the fitted parameters to have the formal error set: it will apply the 
+      // max of the formal and bootstrap errors
       BootstrapRobustStats (&fitPar, fitStats->fit, fitStats->Nfit, FIT_RESULT_RA);
       BootstrapRobustStats (&fitPar, fitStats->fit, fitStats->Nfit, FIT_RESULT_DEC);
@@ -224,4 +234,5 @@
     }
 
+  skipParallaxBootstrap:
     // project Ro, Do back to RA,DEC
     XY_to_RD (&fitPar.Ro, &fitPar.Do, fitPar.Ro, fitPar.Do, &fitStats->coords);
@@ -242,7 +253,5 @@
     valid = valid && (fabs(fitPar.uD) < 4.0);
     valid = valid && (fabs(fitPar.p) < 2.0);
-    if (!valid) {
-      mode = FIT_PM_ONLY;
-    } else {
+    if (valid) {
       average[0].flags |= ID_OBJ_USE_PAR;
     }
@@ -254,44 +263,55 @@
   if ((mode == FIT_PM_ONLY) || (mode == FIT_PM_AND_PAR)) {
     if (Trange < PM_DT_MIN) {
-      mode = FIT_AVERAGE;
       goto justPosition;
     }
     if (fitStats->Npoints < PM_MIN_NPTS) {
-      mode = FIT_AVERAGE;
       goto justPosition;
     }
 
     // if we have fitted (and accepted) a parallax model, get the best pm fit and chisq
-    // given the set of points (mask is respected)
-    if (average[0].flags & ID_OBJ_USE_PAR) {
+    // given the set of points (mask is respected).  Alternatively, if we do not request
+    // IRLS fitting, the just use OLS fitting (skip bootstrap)
+    if ((average[0].flags & ID_OBJ_USE_PAR) || !USE_IRLS) {
       if (!FitPM_Basic (&fitPM, fitStats->fitdataPM, fitStats->points, fitStats->Npoints)) {
 	average[0].flags |= ID_OBJ_BAD_PM;
 	goto justPosition;
       }
-    } else {
-      fitStats->fitdataPM->getError = !N_BOOTSTRAP_SAMPLES;
-      if (!FitPM_IRLS (&fitPM, fitStats->fitdataPM, fitStats->points, fitStats->Npoints)) {
-	mode = FIT_AVERAGE;
-	goto justPosition;
-      }
-      if (N_BOOTSTRAP_SAMPLES) {
-	fitStats->Nfit = 0;
-	int Nnomask = BootstrapSaveUnmasked (fitStats->nomask, fitStats->points, fitStats->Npoints);
-	if (Nnomask < PM_MIN_NPTS_BOOT) {
-	  mode = FIT_AVERAGE;
-	  goto justPosition;
-	}
-	for (k = 0; k < fitStats->NfitAlloc; k++) {
-	  BootstrapResample (fitStats->sample, fitStats->nomask, Nnomask);
-	  if (!FitPM_Basic (&fitStats->fit[k], fitStats->fitdataPM, fitStats->sample, Nnomask)) continue;
-	  fitStats->Nfit ++;
-	}
-	BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_RA);
-	BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_DEC);
-	BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_uR);
-	BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_uD);
-      }
-    }
-
+      goto skipProperMotionBootstrap;
+    } 
+
+    // we are going to use the IRLS analysis to calculate the mean solution and the masking
+    // then run N_BOOTSTRAP_SAMPLES to measure the errors.  We first measure the OLS error,
+    // and choose the max of the OLS and bootstrap errors
+    fitStats->fitdataPM->getError = TRUE;
+    if (!FitPM_IRLS (&fitPM, fitStats->fitdataPM, fitStats->points, fitStats->Npoints)) {
+      goto justPosition;
+    }
+
+    // in the fits above, we have saved the formal error for the unmasked points.  
+    // if we do not have enough points for bootstrap, we will keep those errors
+    if (N_BOOTSTRAP_SAMPLES && (fitPM.Nfit >= PM_MIN_NPTS_BOOT)) {
+      fitStats->Nfit = 0;
+      int Nnomask = BootstrapSaveUnmasked (fitStats->nomask, fitStats->points, fitStats->Npoints);
+	
+      // if we do not have enough points to assess p.m. error, skip the bootstrap analysis.
+      // (I think the test above means we never do this skip)
+      if (Nnomask < PM_MIN_NPTS_BOOT) goto skipProperMotionBootstrap;
+
+      for (k = 0; k < fitStats->NfitAlloc; k++) {
+	BootstrapResample (fitStats->sample, fitStats->nomask, Nnomask);
+	if (!FitPM_Basic (&fitStats->fit[k], fitStats->fitdataPM, fitStats->sample, Nnomask)) continue;
+	fitStats->Nfit ++;
+      }
+
+      // These calls set the ERRORS on the fit parameters, not the fit values (set in IRLS above)
+      // this call expects the fitted parameters to have the formal error set: it will apply the 
+      // max of the formal and bootstrap errors
+      BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_RA);
+      BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_DEC);
+      BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_uR);
+      BootstrapRobustStats (&fitPM, fitStats->fit, fitStats->Nfit, FIT_RESULT_uD);
+    }
+
+skipProperMotionBootstrap:
     // project Ro, Do back to RA,DEC
     XY_to_RD (&fitPM.Ro, &fitPM.Do, fitPM.Ro, fitPM.Do, &fitStats->coords);
@@ -300,4 +320,5 @@
     fitStats->Npm ++;
 
+    // XXX a hard-wired hack...
     // unless there is a clear problems (below) with the proper-motion fit or we have a parallax fit, we will use pm fit
     int valid = TRUE;
@@ -309,5 +330,4 @@
     valid = valid && (fabs(fitPM.uD) < 4.0);
     if (!valid) {
-      mode = FIT_AVERAGE;
       average[0].flags |= ID_OBJ_BAD_PM;
     } else {
@@ -323,59 +343,56 @@
     // if we only have one point, this is silly...
 
+    // set the proper motion (to the galaxy model or average value, if desired; else to 0,0)
     FitAstromResultSetPM (&fitPos, 1, average);
-    // fprintf (stderr, "fit 1: %f %f : %f %f\n", fitPos.Ro, fitPos.Do, fitPos.uR, fitPos.uD);
-    if (average[0].flags & (ID_OBJ_USE_PAR | ID_OBJ_USE_PM)) {
+
+    // if we already have a valid fit (pm or par), use OLS to fit the position
+    // alternatively, if we do not request IRLS, use OLS
+    // alternatively, if we do not have enough points, use OLS
+    if ((average[0].flags & (ID_OBJ_USE_PAR | ID_OBJ_USE_PM)) || (fitStats->Npoints < POS_MIN_NPTS) || !USE_IRLS) {
       if (!FitPosPMfixed_Basic (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) { 
-	// if this fails, stick with the PM and/or PAR fit from above
+	// if this fails, stick with the PM and/or PAR fit from above, or use a single value
 	goto doneWithFit;
       }
-    } else {
-      if (fitStats->Npoints < POS_MIN_NPTS) {
-	// I will not try to outlier-reject, just calculate the weighted average
-	if (!FitPosPMfixed_Basic (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) { 
-	  // if we have tried this, we have not masked any points; we will find a single unmasked point below
-	  goto doneWithFit;
-	}
+      // if we have not already gotten a good fit, use this fit
+      if (!(average[0].flags & (ID_OBJ_USE_PAR | ID_OBJ_USE_PM))) {
 	average[0].flags |= ID_OBJ_USE_AVE;
 	average[0].flags |= ID_OBJ_RAW_AVE;
-	goto useBasic;
-      }
-      if (!FitPosPMfixed_IRLS (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) {
-	// if the above fails, we need to clear the masks and try again below
-	FitPointsClearMasks (fitStats->points, fitStats->Npoints); 
-	// just calculate the weighted average
-	if (!FitPosPMfixed_Basic (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) { 
-	  // if this fails, find a single unmasked point below
-	  goto doneWithFit;
-	}
-	average[0].flags |= ID_OBJ_USE_AVE;
-	average[0].flags |= ID_OBJ_RAW_AVE;
-	goto useBasic;
-      }
-      // fprintf (stderr, "fit 2: %f %f : %f %f\n", fitPos.Ro, fitPos.Do, fitPos.uR, fitPos.uD);
-      if (N_BOOTSTRAP_SAMPLES) {
-	fitStats->Nfit = 0;
-	int Nnomask = BootstrapSaveUnmasked (fitStats->nomask, fitStats->points, fitStats->Npoints);
-	if (Nnomask < POS_MIN_NPTS_BOOT) {
-	  // if the above fails, we need to clear the masks and try again below
-	  FitPointsClearMasks (fitStats->points, fitStats->Npoints); 
-	  if (!FitPosPMfixed_Basic (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) { 
-	    // if this fails, find a single unmasked point below
-	    goto doneWithFit;
-	  }
-	  average[0].flags |= ID_OBJ_USE_AVE;
-	  average[0].flags |= ID_OBJ_RAW_AVE;
-	  goto useBasic;
-	}
-	FitAstromResultSetPM (fitStats->fit, fitStats->NfitAlloc, average);
-	for (k = 0; k < fitStats->NfitAlloc; k++) {
-	  BootstrapResample (fitStats->sample, fitStats->nomask, Nnomask);
-	  if (!FitPosPMfixed_Basic (&fitStats->fit[k], fitStats->fitdataPos, fitStats->sample, Nnomask)) continue;
-	  fitStats->Nfit ++;
-	}
-	BootstrapRobustStats (&fitPos, fitStats->fit, fitStats->Nfit, FIT_RESULT_RA);
-	BootstrapRobustStats (&fitPos, fitStats->fit, fitStats->Nfit, FIT_RESULT_DEC);
+      }
+      goto useBasic;
+    } 
+    
+    // try the IRLS fitting, otherwise give up and use OLS
+    if (!FitPosPMfixed_IRLS (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) {
+      // if the above fails, we need to clear the masks and try again below
+      FitPointsClearMasks (fitStats->points, fitStats->Npoints); 
+      // just calculate the weighted average
+      if (!FitPosPMfixed_Basic (&fitPos, fitStats->fitdataPos, fitStats->points, fitStats->Npoints)) { 
+	// if this fails, find a single unmasked point below
+	goto doneWithFit;
       }
       average[0].flags |= ID_OBJ_USE_AVE;
+      average[0].flags |= ID_OBJ_RAW_AVE;
+      goto useBasic;
+    }
+    average[0].flags |= ID_OBJ_USE_AVE;
+
+    if (N_BOOTSTRAP_SAMPLES && (fitPos.Nfit >= POS_MIN_NPTS_BOOT)) {
+      fitStats->Nfit = 0;
+      int Nnomask = BootstrapSaveUnmasked (fitStats->nomask, fitStats->points, fitStats->Npoints);
+      
+      if (Nnomask < POS_MIN_NPTS_BOOT) goto useBasic;
+      
+      FitAstromResultSetPM (fitStats->fit, fitStats->NfitAlloc, average);
+      for (k = 0; k < fitStats->NfitAlloc; k++) {
+	BootstrapResample (fitStats->sample, fitStats->nomask, Nnomask);
+	if (!FitPosPMfixed_Basic (&fitStats->fit[k], fitStats->fitdataPos, fitStats->sample, Nnomask)) continue;
+	fitStats->Nfit ++;
+      }
+      
+      // These calls set the ERRORS on the fit parameters, not the fit values (set in IRLS above)
+      // this call expects the fitted parameters to have the formal error set: it will apply the 
+      // max of the formal and bootstrap errors
+      BootstrapRobustStats (&fitPos, fitStats->fit, fitStats->Nfit, FIT_RESULT_RA);
+      BootstrapRobustStats (&fitPos, fitStats->fit, fitStats->Nfit, FIT_RESULT_DEC);
     }
 
@@ -544,4 +561,5 @@
   average[0].dP         = fit.dp; // parallax error in arcsec
 
+
   average[0].ChiSqAve   = fitPos.chisq;
   average[0].ChiSqPM    = fitPM.chisq;
@@ -666,4 +684,6 @@
 
   int has2MASS = FALSE;
+  int hasGAIA  = FALSE;
+  int hasTycho = FALSE;
   int hasStack = FALSE;
   if (stackEntry) *stackEntry = -1;
@@ -774,7 +794,7 @@
     Npoints++;
 
-    if ((measure[k].photcode >= 2011) && (measure[k].photcode <= 2013)) {
-      has2MASS = TRUE;
-    }
+    hasGAIA  =  (measure[k].photcode == 1030);
+    has2MASS = ((measure[k].photcode >= 2011) && (measure[k].photcode <= 2013));
+    hasTycho = ((measure[k].photcode >= 2020) && (measure[k].photcode <= 2021));
 
     myAssert (Npoints <= fit->NpointsAlloc, "oops");
@@ -796,4 +816,14 @@
       measure[k].dbFlags &= ~ID_MEAS_OBJECT_HAS_2MASS;
     }
+    if (hasGAIA) {
+      measure[k].dbFlags |=  ID_MEAS_OBJECT_HAS_GAIA;
+    } else {
+      measure[k].dbFlags &= ~ID_MEAS_OBJECT_HAS_GAIA;
+    }
+    if (hasTycho) {
+      measure[k].dbFlags |=  ID_MEAS_OBJECT_HAS_TYCHO;
+    } else {
+      measure[k].dbFlags &= ~ID_MEAS_OBJECT_HAS_TYCHO;
+    }
   }
 
@@ -803,4 +833,6 @@
   if (hasStack) status |= SELECT_MEAS_HAS_STACK; 
   if (has2MASS) status |= SELECT_MEAS_HAS_2MASS; 
+  if (hasGAIA)  status |= SELECT_MEAS_HAS_GAIA; 
+  if (hasTycho) status |= SELECT_MEAS_HAS_TYCHO; 
   return status;
 }
@@ -822,4 +854,6 @@
 
   int i;
+
+  myAbort ("this should not be called anymore");
 
   // add up the chi square for the fit
@@ -852,8 +886,13 @@
   int i;
 
-  if (USE_GALAXY_MODEL) {
+  if (APPLY_PROPER_MOTION) {
     for (i = 0; i < Nfit; i++) {
-      fit[i].uR = average->uRgal;
-      fit[i].uD = average->uDgal;
+      if (USE_GALAXY_MODEL) {
+	fit[i].uR = average->uRgal;
+	fit[i].uD = average->uDgal;
+      } else {
+	fit[i].uR = average->uR;
+	fit[i].uD = average->uD;
+      }
     }
   } else {
Index: trunk/Ohana/src/relastro/src/UpdateStacks.c
===================================================================
--- trunk/Ohana/src/relastro/src/UpdateStacks.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/UpdateStacks.c	(revision 39926)
@@ -3,4 +3,6 @@
 // NOTE: we only measure the systematic floor of the astrometric scatter per stack, no change to the calibration
 int UpdateStacks (Catalog *catalog, int Ncatalog) {
+
+  if (SKIP_PS1_STACK) return TRUE;
 
   off_t Nimage;
@@ -46,6 +48,6 @@
 
     // XXX: I need to convert dLsig, dMsig from degrees to pixels
-    dLsig *= 3600.0 / 0.25;
-    dMsig *= 3600.0 / 0.25;
+    dLsig *= 3600.0;
+    dMsig *= 3600.0;
 
     image[i].dXpixSys = dLsig;
Index: trunk/Ohana/src/relastro/src/args.c
===================================================================
--- trunk/Ohana/src/relastro/src/args.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/args.c	(revision 39926)
@@ -1,8 +1,9 @@
 # include "relastro.h"
-void usage (void);
-void usage_client (void);
+void usage (int argc, char **argv);
+void usage_client (int argc, char **argv);
 void usage_merge_source (void);
 void usage_merge_source_id (char *name);
 float *ParseLoopWeights (char *rawlist);
+int *ParseLoopOrder (char *rawlist, int minValue);
 
 int args (int argc, char **argv) {
@@ -39,5 +40,5 @@
     remove_argument (N, &argc, argv);
 
-    if (argc != 1) usage ();
+    if (argc != 1) usage (argc, argv);
     return TRUE;
   }
@@ -76,4 +77,11 @@
     remove_argument (N, &argc, argv);
     CHECK_MEASURE_TO_IMAGE = TRUE;
+  }
+
+  // catch-up mode : for a re-run, allow the sync file to be ahead of the desired location:
+  CATCH_UP = FALSE;
+  if ((N = get_argument (argc, argv, "-catch-up"))) {
+    remove_argument (N, &argc, argv);
+    CATCH_UP = TRUE;
   }
 
@@ -105,8 +113,8 @@
     remove_argument (N, &argc, argv);
     RELASTRO_OP = OP_PARALLEL_IMAGES;
-    if (N >= argc) usage();
+    if (N >= argc) usage (argc, argv);
     IMAGE_TABLE = strcreate (argv[N]);
     remove_argument (N, &argc, argv);
-    if (!REGION_FILE) usage();
+    if (!REGION_FILE) usage (argc, argv);
   }
 
@@ -114,4 +122,81 @@
     remove_argument (N, &argc, argv);
     RELASTRO_OP = OP_IMAGES;
+  }
+
+  // used to decide if changes to the image parameters get applied to the measures
+  APPLY_OFFSETS = FALSE;
+  if ((N = get_argument (argc, argv, "-apply-offsets"))) {
+    remove_argument (N, &argc, argv);
+    APPLY_OFFSETS = TRUE;
+  }
+
+  APPLY_PROPER_MOTION = FALSE;
+  if ((N = get_argument (argc, argv, "-apply-proper-motion"))) {
+    remove_argument (N, &argc, argv);
+    APPLY_PROPER_MOTION = TRUE;
+  }
+
+  SKIP_PS1_CHIP = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-ps1-chip"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_PS1_CHIP = TRUE;
+  }
+  SKIP_PS1_STACK = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-ps1-stack"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_PS1_STACK = TRUE;
+  }
+  SKIP_HSC = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-hsc"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_HSC = TRUE;
+  }
+  SKIP_CFH = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-cfh"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_CFH = TRUE;
+  }
+
+  UPDATE_PS1_STACK_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-ps1-stack"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_PS1_STACK_MEASURE = TRUE;
+  }
+  UPDATE_PS1_CHIP_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-ps1-chip"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_PS1_CHIP_MEASURE = TRUE;
+  }
+  UPDATE_HSC_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-hsc"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_HSC_MEASURE = TRUE;
+  }
+  UPDATE_CFH_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-cfh"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_CFH_MEASURE = TRUE;
+  }
+  if (RELASTRO_OP == OP_UPDATE_OFFSETS) {
+    if (!UPDATE_PS1_STACK_MEASURE && !UPDATE_PS1_CHIP_MEASURE && !UPDATE_HSC_MEASURE && !UPDATE_CFH_MEASURE) {
+      fprintf (stderr, "for -update-offsets, need to select at least one of -update-ps1-stack, -update-ps1-chip, -update-hsc, -update-cfh\n");
+      exit (2);
+    }
+  }
+  if ((RELASTRO_OP == OP_PARALLEL_IMAGES) || (RELASTRO_OP == OP_IMAGES)) {
+    if (APPLY_OFFSETS && !UPDATE_PS1_STACK_MEASURE && !UPDATE_PS1_CHIP_MEASURE && !UPDATE_HSC_MEASURE && !UPDATE_CFH_MEASURE) {
+      fprintf (stderr, "for [-images or -parallel-images] with -apply-offsets, need to select at least one of -update-ps1-stack, -update-ps1-chip, -update-hsc, -update-cfh\n");
+      exit (2);
+    }
+  }
+
+  // for fitting objects, this is always the same as 'ALLOW_IRLS' below, but for fitting
+  // images, this is set to FALSE while doing the fit for the image parameters
+  USE_IRLS = TRUE;  
+  ALLOW_IRLS = TRUE;
+  if ((N = get_argument (argc, argv, "-no-irls"))) {
+    remove_argument (N, &argc, argv);
+    USE_IRLS = FALSE;
+    ALLOW_IRLS = FALSE;
   }
 
@@ -120,5 +205,5 @@
     remove_argument (N, &argc, argv);
     RELASTRO_OP = OP_PARALLEL_REGIONS;
-    if (!REGION_FILE) usage();
+    if (!REGION_FILE) usage (argc, argv);
     if ((N = get_argument (argc, argv, "-parallel-regions-manual"))) {
       remove_argument (N, &argc, argv);
@@ -128,22 +213,22 @@
 
   if ((N = get_argument (argc, argv, "-testobj1"))) {
-    if (N > argc - 3) usage ();
+    if (N > argc - 3) usage (argc, argv);
     remove_argument (N, &argc, argv);
     OBJ_ID_SRC = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage ();
+    if (*endptr) usage (argc, argv);
     remove_argument (N, &argc, argv);
     CAT_ID_SRC = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage (); 
+    if (*endptr) usage (argc, argv); 
     remove_argument (N, &argc, argv);
   }
 
   if ((N = get_argument (argc, argv, "-testobj2"))) {
-    if (N > argc - 3) usage ();
+    if (N > argc - 3) usage (argc, argv);
     remove_argument (N, &argc, argv);
     OBJ_ID_DST = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage ();
+    if (*endptr) usage (argc, argv);
     remove_argument (N, &argc, argv);
     CAT_ID_DST = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage (); 
+    if (*endptr) usage (argc, argv); 
     remove_argument (N, &argc, argv);
   }
@@ -167,5 +252,5 @@
   if ((N = get_argument (argc, argv, "-high-speed"))) {
     // XXX include a parallax / no-parallax option
-    if (N >= argc - 4) usage();
+    if (N >= argc - 4) usage (argc, argv);
     RELASTRO_OP = OP_HIGH_SPEED;
     remove_argument (N, &argc, argv);
@@ -181,5 +266,5 @@
 
   if ((N = get_argument (argc, argv, "-hpm"))) {
-    if (N >= argc - 2) usage();
+    if (N >= argc - 2) usage (argc, argv);
     RELASTRO_OP = OP_HPM;
     remove_argument (N, &argc, argv);
@@ -212,4 +297,8 @@
     FIT_TARGET = TARGET_MOSAICS;
   }
+  if ((N = get_argument (argc, argv, "-set-chips"))) {
+    remove_argument (N, &argc, argv);
+    FIT_TARGET = SET_CHIPS;
+  }
 
   FlagOutlier = FALSE;
@@ -231,7 +320,7 @@
   }
 
-  if (RELASTRO_OP == OP_NONE) usage();
-
-  if (((RELASTRO_OP == OP_IMAGES) || (RELASTRO_OP == OP_PARALLEL_REGIONS) || (RELASTRO_OP == OP_PARALLEL_IMAGES)) && (FIT_TARGET == TARGET_NONE)) usage();
+  if (RELASTRO_OP == OP_NONE) usage (argc, argv);
+
+  if (((RELASTRO_OP == OP_IMAGES) || (RELASTRO_OP == OP_PARALLEL_REGIONS) || (RELASTRO_OP == OP_PARALLEL_IMAGES)) && (FIT_TARGET == TARGET_NONE)) usage (argc, argv);
 
   /* specify portion of the sky : allow default of all sky? */
@@ -303,4 +392,10 @@
   }
 
+  KEEP_ALL_IMAGES_RA = FALSE;
+  if ((N = get_argument (argc, argv, "-keep-all-images-ra"))) {
+    remove_argument (N, &argc, argv);
+    KEEP_ALL_IMAGES_RA = TRUE;
+  }
+
   USE_BASIC_CHECK = FALSE;
   if ((N = get_argument (argc, argv, "-basic-image-search"))) {
@@ -315,10 +410,4 @@
     remove_argument (N, &argc, argv);
     MaxDensityUse = TRUE;
-  }
-
-  APPLY_OFFSETS = FALSE;
-  if ((N = get_argument (argc, argv, "-apply-offsets"))) {
-    remove_argument (N, &argc, argv);
-    APPLY_OFFSETS = TRUE;
   }
 
@@ -439,19 +528,4 @@
   }
 
-  CHIPORDER = 0;
-  if ((N = get_argument (argc, argv, "-chiporder"))) {
-    remove_argument (N, &argc, argv);
-    CHIPORDER = atoi(argv[N]);
-    remove_argument (N, &argc, argv);
-  }
-
-  CHIPMAP = 0;
-  if ((N = get_argument (argc, argv, "-chipmap"))) {
-    remove_argument (N, &argc, argv);
-    CHIPMAP = atoi(argv[N]);
-    remove_argument (N, &argc, argv);
-
-  }
-
   SAVEPLOT = FALSE;
   PLOTSTUFF = FALSE;
@@ -580,4 +654,38 @@
   }
 
+  // e.g., -chiporderloop 3,4,5
+  // NOTE: this must come after -nloop above
+  ChipOrderLoop = NULL;
+  ChipOrderLoopStr = NULL;
+  CHIPORDER = 1;
+  if ((N = get_argument (argc, argv, "-chiporder"))) {
+    remove_argument (N, &argc, argv);
+    CHIPORDER = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-chiporderloop"))) {
+    remove_argument (N, &argc, argv);
+    ChipOrderLoopStr = strcreate(argv[N]);
+    ChipOrderLoop = ParseLoopOrder (argv[N], 1);
+    remove_argument (N, &argc, argv);
+  }
+
+  ChipMapLoop = NULL;
+  ChipMapLoopStr = NULL;
+  CHIPMAP = 0;
+  if ((N = get_argument (argc, argv, "-chipmap"))) {
+    remove_argument (N, &argc, argv);
+    CHIPMAP = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+
+  }
+  if ((N = get_argument (argc, argv, "-chipmaploop"))) {
+    remove_argument (N, &argc, argv);
+    ChipMapLoopStr = strcreate(argv[N]);
+    ChipMapLoop = ParseLoopOrder (argv[N], 0);
+    remove_argument (N, &argc, argv);
+  }
+  
+
   // e.g., -loop-weights-2mass 1000,300,300,200,200,100
   // NOTE: this must come after -nloop above
@@ -591,4 +699,5 @@
   }
   LoopWeightTycho = NULL;
+  LoopWeightTychostr = NULL;
   if ((N = get_argument (argc, argv, "-loop-weights-tycho"))) {
     remove_argument (N, &argc, argv);
@@ -597,4 +706,28 @@
     remove_argument (N, &argc, argv);
   }
+  LoopWeightGAIA = NULL;
+  LoopWeightGAIAstr = NULL;
+  if ((N = get_argument (argc, argv, "-loop-weights-gaia"))) {
+    remove_argument (N, &argc, argv);
+    LoopWeightGAIAstr = strcreate(argv[N]);
+    LoopWeightGAIA = ParseLoopWeights (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (argc, argv, "-galaxy-model"))) {
+    remove_argument (N, &argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("FEAST-HIPPARCOS");
+
+  // for testing, allow the galaxy model scale to be non-unity
+  TEST_SCALE = 1.0;
+  if ((N = get_argument (argc, argv, "-testing"))) {
+    remove_argument (N, &argc, argv);
+    TEST_SCALE = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
 
   NTHREADS = 0;
@@ -605,5 +738,5 @@
   }
 
-  if (argc != 1) usage ();
+  if (argc != 1) usage (argc, argv);
   return TRUE;
 }
@@ -614,4 +747,13 @@
   FREE (LoopWeight2MASSstr);
   FREE (LoopWeightTychostr);
+  FREE (LoopWeightGAIAstr);
+  FREE (LoopWeight2MASS);
+  FREE (LoopWeightTycho);
+  FREE (LoopWeightGAIA);
+
+  FREE (ChipMapLoop);
+  FREE (ChipMapLoopStr);
+  FREE (ChipOrderLoop);
+  FREE (ChipOrderLoopStr);
 
   FREE (PHOTCODE_SKIP_LIST);
@@ -628,4 +770,5 @@
   FREE (BCATALOG);
   FREE (HOSTDIR);
+  FREE (GALAXY_MODEL);
 
   // these are set in initialize
@@ -673,5 +816,5 @@
     remove_argument (N, &argc, argv);
   }
-  if (!HOST_ID) usage_client();
+  if (!HOST_ID) usage_client (argc, argv);
 
   HOSTDIR = NULL;
@@ -681,5 +824,5 @@
     remove_argument (N, &argc, argv);
   }
-  if (!HOSTDIR) usage_client();
+  if (!HOSTDIR) usage_client (argc, argv);
 
   if ((N = get_argument (argc, argv, "-load-objects"))) {
@@ -726,4 +869,52 @@
   }
 
+  SKIP_PS1_CHIP = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-ps1-chip"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_PS1_CHIP = TRUE;
+  }
+  SKIP_PS1_STACK = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-ps1-stack"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_PS1_STACK = TRUE;
+  }
+  SKIP_HSC = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-hsc"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_HSC = TRUE;
+  }
+  SKIP_CFH = FALSE;
+  if ((N = get_argument (argc, argv, "-skip-cfh"))) {
+    remove_argument (N, &argc, argv);
+    SKIP_CFH = TRUE;
+  }
+
+  UPDATE_PS1_STACK_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-ps1-stack"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_PS1_STACK_MEASURE = TRUE;
+  }
+  UPDATE_PS1_CHIP_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-ps1-chip"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_PS1_CHIP_MEASURE = TRUE;
+  }
+  UPDATE_HSC_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-hsc"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_HSC_MEASURE = TRUE;
+  }
+  UPDATE_CFH_MEASURE = FALSE;
+  if ((N = get_argument (argc, argv, "-update-cfh"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE_CFH_MEASURE = TRUE;
+  }
+  if (RELASTRO_OP == OP_UPDATE_OFFSETS) {
+    if (!UPDATE_PS1_STACK_MEASURE && !UPDATE_PS1_CHIP_MEASURE && !UPDATE_HSC_MEASURE && !UPDATE_CFH_MEASURE) {
+      fprintf (stderr, "for -update-offsets, need to select at least one of -update-ps1-stack, -update-ps1-chip, -update-hsc, -update-cfh\n");
+      exit (2);
+    }
+  }
+
   // check for object fitting modes
   if ((N = get_argument (argc, argv, "-pm"))) {
@@ -742,5 +933,5 @@
   if ((N = get_argument (argc, argv, "-high-speed"))) {
     // XXX include a parallax / no-parallax option
-    if (N >= argc - 5) usage_client();
+    if (N >= argc - 5) usage_client (argc, argv);
     RELASTRO_OP = OP_HIGH_SPEED;
     remove_argument (N, &argc, argv);
@@ -756,5 +947,5 @@
 
   if ((N = get_argument (argc, argv, "-hpm"))) {
-    if (N >= argc - 3) usage();
+    if (N >= argc - 3) usage_client (argc, argv);
     RELASTRO_OP = OP_HPM;
     remove_argument (N, &argc, argv);
@@ -766,22 +957,22 @@
 
   if ((N = get_argument (argc, argv, "-testobj1"))) {
-    if (N > argc - 3) usage ();
+    if (N > argc - 3) usage_client (argc, argv);
     remove_argument (N, &argc, argv);
     OBJ_ID_SRC = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage ();
+    if (*endptr) usage_client (argc, argv);
     remove_argument (N, &argc, argv);
     CAT_ID_SRC = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage (); 
+    if (*endptr) usage_client (argc, argv); 
     remove_argument (N, &argc, argv);
   }
 
   if ((N = get_argument (argc, argv, "-testobj2"))) {
-    if (N > argc - 3) usage ();
+    if (N > argc - 3) usage_client (argc, argv);
     remove_argument (N, &argc, argv);
     OBJ_ID_DST = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage ();
+    if (*endptr) usage_client (argc, argv);
     remove_argument (N, &argc, argv);
     CAT_ID_DST = strtol(argv[N], &endptr, 0);
-    if (*endptr) usage (); 
+    if (*endptr) usage_client (argc, argv); 
     remove_argument (N, &argc, argv);
   }
@@ -805,5 +996,21 @@
   }
 
-  if (RELASTRO_OP == OP_NONE) usage_client();
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (argc, argv, "-galaxy-model"))) {
+    remove_argument (N, &argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("FEAST-HIPPARCOS");
+
+  // for testing, allow the galaxy model scale to be non-unity
+  TEST_SCALE = 1.0;
+  if ((N = get_argument (argc, argv, "-testing"))) {
+    remove_argument (N, &argc, argv);
+    TEST_SCALE = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (RELASTRO_OP == OP_NONE) usage_client (argc, argv);
 
   /* specify portion of the sky : allow default of all sky? */
@@ -1032,5 +1239,5 @@
   }
 
-  if (argc != 1) usage_client ();
+  if (argc != 1) usage_client (argc, argv);
   return TRUE;
 }
@@ -1049,5 +1256,6 @@
   FREE(HIGH_SPEED_DIR);
   FREE(BCATALOG);
-  FREE (HOSTDIR);
+  FREE(HOSTDIR);
+  FREE(GALAXY_MODEL);
 
   // these are set in initialize
@@ -1066,5 +1274,5 @@
 }
 
-void usage () {
+void usage (int argc, char **argv) {
   fprintf (stderr, "ERROR: USAGE: relastro -images -update-simple [options]\n");
   fprintf (stderr, "       OR:    relastro -images -update-chips [options]\n");
@@ -1116,8 +1324,15 @@
   fprintf (stderr, "  -v\n");
   fprintf (stderr, "  \n");
+
+  fprintf (stderr, "remaining args: ");
+  for (int i = 0; i < argc; i++) {
+    fprintf (stderr, "%s ", argv[i]);
+  }
+  fprintf (stderr, "\n");
+
   exit (2);
 } 
 
-void usage_client () {
+void usage_client (int argc, char **argv) {
   fprintf (stderr, "ERROR: USAGE: relastro_client -load\n");
   fprintf (stderr, "       OR:    relastro_client -update-offsets\n");
@@ -1150,4 +1365,11 @@
   fprintf (stderr, "  -v\n");
   fprintf (stderr, "  \n");
+
+  fprintf (stderr, "remaining args: ");
+  for (int i = 0; i < argc; i++) {
+    fprintf (stderr, "%s ", argv[i]);
+  }
+  fprintf (stderr, "\n");
+
   exit (2);
 } 
@@ -1189,8 +1411,49 @@
   }
 
+  // this sets the last loops to match the last value...
   while (Nloop < NLOOP) {
     weights[Nloop] = weights[Nloop - 1];
     Nloop ++;
   }
+
   return weights;
 }
+
+int *ParseLoopOrder (char *rawlist, int minValue) {
+
+  int *orders = NULL;
+  ALLOCATE (orders, int, NLOOP);
+
+  int Nloop = 0;
+
+  /* parse the comma-separated list of photcodes */
+  char *myList = strcreate(rawlist);
+  char *list = myList;
+  char *entry = NULL;
+  char *ptr = NULL;
+  while ((Nloop < NLOOP) && ((entry = strtok_r (list, ",", &ptr)) != NULL)) {
+    list = NULL; // pass NULL on successive strtok_r calls
+
+    orders[Nloop] = atoi(entry);
+    if (orders[Nloop] < minValue) {
+      fprintf (stderr, "order cannot be < %d: %s\n", minValue, rawlist);
+      exit (3);
+    }
+
+    Nloop ++;
+  }
+  free (myList);
+
+  if (Nloop == 0) {
+    fprintf (stderr, "syntax error parsing orders: %s\n", rawlist);
+    exit (3);
+  }
+
+  // this sets the last loops to match the last value...
+  while (Nloop < NLOOP) {
+    orders[Nloop] = orders[Nloop - 1];
+    Nloop ++;
+  }
+
+  return orders;
+}
Index: trunk/Ohana/src/relastro/src/assign_images.c
===================================================================
--- trunk/Ohana/src/relastro/src/assign_images.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/assign_images.c	(revision 39926)
@@ -40,5 +40,5 @@
 
   // register the image array with ImageOps.c for later getimageByID calls
-  initImages (image, NULL, Nimage);
+  initImages (image, NULL, Nimage, FALSE);
 
   if (VERBOSE) fprintf (stderr, "finding images\n");
@@ -72,4 +72,10 @@
 
   for (j = 0; j < Nimage; j++) {
+    
+    // allow certain cameras to stay static
+    if (SKIP_PS1_CHIP  && isGPC1chip (image[j].photcode)) continue;
+    if (SKIP_PS1_STACK && isGPC1stack(image[j].photcode)) continue;
+    if (SKIP_HSC       && isHSCchip  (image[j].photcode)) continue;
+    if (SKIP_CFH       && isCFHchip  (image[j].photcode)) continue;
     
     /* select images by photcode, or equiv photcode, if specified */
Index: trunk/Ohana/src/relastro/src/bcatalog.c
===================================================================
--- trunk/Ohana/src/relastro/src/bcatalog.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/bcatalog.c	(revision 39926)
@@ -72,4 +72,6 @@
 
   int myNskip1 = 0, myNskip2 = 0, myNskip3 = 0, myNskip4 = 0, myNskip5 = 0, myNskip6 = 0;
+
+  int NgaiaObject = 0;
 
   /* exclude stars not in range or with too few measurements */
@@ -187,4 +189,10 @@
       if (isGPC1warp(catalog[0].measure[offset].photcode)) continue;
 
+      // allow certain cameras to stay static
+      if (SKIP_PS1_CHIP  && isGPC1chip(catalog[0].measure[offset].photcode)) continue;
+      if (SKIP_PS1_STACK && isGPC1stack(catalog[0].measure[offset].photcode)) continue;
+      if (SKIP_HSC       && isHSCchip(catalog[0].measure[offset].photcode)) continue;
+      if (SKIP_CFH       && isCFHchip(catalog[0].measure[offset].photcode)) continue;
+
       // filter objects based on user supplied criteria, including SIGMA_LIM
       if (!MeasFilterTest(&catalog[0].measure[offset], TRUE)) {
@@ -250,4 +258,6 @@
       }
 
+      if (catalog[0].measure[offset].photcode == 1030) { NgaiaObject ++; }
+
       CopyMeasureToTiny (&subcatalog[0].measureT[Nmeasure], &catalog[0].measure[offset]);
       // subcatalog[0].measure[Nmeasure] = catalog[0].measure[offset];
@@ -281,5 +291,5 @@
     }
   }
-  fprintf (stderr, "skips: %d %d %d %d %d %d\n", myNskip1, myNskip2, myNskip3, myNskip4, myNskip5, myNskip6);
+  fprintf (stderr, "skips: %d %d %d %d %d %d, Ngaia: %d\n", myNskip1, myNskip2, myNskip3, myNskip4, myNskip5, myNskip6, NgaiaObject);
   REALLOCATE (subcatalog[0].average,  Average,     MAX (Naverage, 1));
   REALLOCATE (subcatalog[0].measureT, MeasureTiny, MAX (Nmeasure, 1));
Index: trunk/Ohana/src/relastro/src/extra.c
===================================================================
--- trunk/Ohana/src/relastro/src/extra.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/extra.c	(revision 39926)
@@ -39,2 +39,26 @@
   return FALSE;
 }
+
+// for now (20160925) I need to identify HSC chips explicitly.  generalize in the future
+int isHSCchip (int photcode) {
+
+  if ((photcode >= 20000) && (photcode <= 20111)) return TRUE; // g-band
+  if ((photcode >= 21000) && (photcode <= 21111)) return TRUE; // r-band
+  if ((photcode >= 22000) && (photcode <= 22111)) return TRUE; // i-band
+  if ((photcode >= 23000) && (photcode <= 23111)) return TRUE; // z-band
+  if ((photcode >= 24000) && (photcode <= 24111)) return TRUE; // y-band
+
+  return FALSE;
+}
+
+// for now (20160925) I need to identify CFH chips explicitly.  generalize in the future
+int isCFHchip (int photcode) {
+
+  if ((photcode >= 100) && (photcode <= 152)) return TRUE; // g-band
+  if ((photcode >= 200) && (photcode <= 252)) return TRUE; // r-band
+  if ((photcode >= 300) && (photcode <= 352)) return TRUE; // i-band
+  if ((photcode >= 400) && (photcode <= 452)) return TRUE; // z-band
+  if ((photcode >= 500) && (photcode <= 552)) return TRUE; // y-band
+
+  return FALSE;
+}
Index: trunk/Ohana/src/relastro/src/initialize.c
===================================================================
--- trunk/Ohana/src/relastro/src/initialize.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/initialize.c	(revision 39926)
@@ -11,4 +11,11 @@
   ConfigInit (&argc, argv);
   args (argc, argv);
+
+  if (USE_GALAXY_MODEL) {
+    if (!InitGalaxyModel (GALAXY_MODEL)) {
+      fprintf (stderr, "failed to init galaxy model %s\n", GALAXY_MODEL);
+      exit (2);
+    }
+  }
 
   if (RELASTRO_OP == OP_MERGE_SOURCE) return;
Index: trunk/Ohana/src/relastro/src/launch_region_hosts.c
===================================================================
--- trunk/Ohana/src/relastro/src/launch_region_hosts.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/launch_region_hosts.c	(revision 39926)
@@ -81,10 +81,26 @@
     strextend (&command, "-region-hosts %s", REGION_FILE);
     strextend (&command, "-region-hostID %d", host->hostID);
+
     strextend (&command, "-D CATDIR %s", CATDIR);
     strextend (&command, "-region %f %f %f %f", host->RminCat, host->RmaxCat, host->DminCat, host->DmaxCat);
     strextend (&command, "-statmode %s", STATMODE);
     strextend (&command, "-minerror %f", MIN_ERROR);
-    strextend (&command, "-nloop %d", NLOOP);
-    strextend (&command, "-threads %d", NTHREADS);
+
+    strextend (&command, "-D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
+    strextend (&command, "-D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
+
+    strextend (&command, " -D RELASTRO_MIN_DISTANCE_MOD %f",     MIN_DISTANCE_MOD);
+    strextend (&command, " -D RELASTRO_MAX_DISTANCE_MOD %f",     MAX_DISTANCE_MOD);
+    strextend (&command, " -D RELASTRO_MAX_DISTANCE_MOD_ERR %f", MAX_DISTANCE_MOD_ERR);
+
+    strextend (&command, "-D USE_GALAXY_MODEL %d", USE_GALAXY_MODEL);
+    strextend (&command, "-D USE_ICRF_CORRECT %d", USE_ICRF_CORRECT);
+
+    strextend (&command, "-D RELASTRO_DPOS_MAX %f", DPOS_MAX);
+    strextend (&command, "-D ADDSTAR_RADIUS %f", ADDSTAR_RADIUS);
+
+    strextend (&command, "-D USE_ICRF_LOCAL %d",   USE_ICRF_LOCAL);
+    strextend (&command, "-D USE_ICRF_SHFIT %d",   USE_ICRF_SHFIT);
+    strextend (&command, "-D USE_ICRF_POLE %d",    USE_ICRF_POLE);
 
     switch (FIT_TARGET) {
@@ -98,4 +114,7 @@
 	strextend (&command, "-update-mosaics");
 	break;
+      case SET_CHIPS:
+	strextend (&command, "-set-chips");
+	break;
       case TARGET_NONE:
 	abort();
@@ -105,28 +124,46 @@
     if (VERBOSE2)      	    strextend (&command, "-vv");
     if (RESET)         	    strextend (&command, "-reset");
+
+    if (ImagSelect)         strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
+    if (MaxDensityUse) 	    strextend (&command, "-max-density %f", MaxDensityValue);
+    if (FlagOutlier)        strextend (&command, "-clip %d", CLIP_THRESH);
+    if (ExcludeBogus)       strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
+
+    if (USE_FIXED_PIXCOORDS) strextend (&command, "-D USE_FIXED_PIXCOORDS 1");
+    if (PHOTCODE_KEEP_LIST) strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST); 
+    if (PHOTCODE_SKIP_LIST) strextend (&command, "-photcode %s", PHOTCODE_SKIP_LIST);
+    if (PhotFlagSelect)     strextend (&command, "+photflags"); 
+    if (PhotFlagBad)        strextend (&command, "+photflagbad %d", PhotFlagBad); 
+    if (PhotFlagPoor)       strextend (&command, "+photflagpoor %d", PhotFlagPoor); 
+
+    if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
+      strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
+    }
+    if (DCR_RED_COLOR_POS && DCR_RED_COLOR_NEG) {
+      strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
+    }
+
+    if (TEST_SCALE != 1.0)   strextend (&command, "-testing %f", TEST_SCALE);
+
+    if (SKIP_PS1_CHIP)       strextend (&command, "-skip-ps1-chip");
+    if (SKIP_PS1_STACK)      strextend (&command, "-skip-ps1-stack");
+    if (SKIP_HSC)            strextend (&command, "-skip-hsc");
+    if (SKIP_CFH)            strextend (&command, "-skip-cfh");
+
+    strextend (&command, "-nloop %d", NLOOP);
+    strextend (&command, "-threads %d", NTHREADS);
+    
+    if (PHOTCODE_RESET_LIST) strextend (&command, "-reset-to-photcode %s", PHOTCODE_RESET_LIST);
+
     if (UPDATE)        	    strextend (&command, "-update");
     if (PARALLEL)      	    strextend (&command, "-parallel");
     if (PARALLEL_MANUAL)    strextend (&command, "-parallel-manual");
     if (PARALLEL_SERIAL)    strextend (&command, "-parallel-serial");
-    if (PHOTCODE_KEEP_LIST) strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST); 
-    if (PHOTCODE_SKIP_LIST) strextend (&command, "-photcode %s", PHOTCODE_SKIP_LIST);
-    if (PHOTCODE_RESET_LIST) strextend (&command, "-reset-to-photcode %s", PHOTCODE_RESET_LIST);
-
-    if (MaxDensityUse) 	    strextend (&command, "-max-density %f", MaxDensityValue);
-    if (ImagSelect)         strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
-    if (ExcludeBogus)       strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
-
-    if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
-      strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
-    }
-    if (DCR_RED_COLOR_POS && DCR_RED_COLOR_NEG) {
-      strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
-    }
-
-    if (PhotFlagSelect)     strextend (&command, "+photflags"); 
-    if (PhotFlagBad)        strextend (&command, "+photflagbad %d", PhotFlagBad); 
-    if (PhotFlagPoor)       strextend (&command, "+photflagpoor %d", PhotFlagPoor); 
-
+
+    strextend (&command, "-chiporder %d", CHIPORDER); 
     if (CHIPMAP)            strextend (&command, "-chipmap %d", CHIPMAP); 
+    if (ChipMapLoop)        strextend (&command, "-chipmaploop %s", ChipMapLoopStr); 
+    if (ChipOrderLoop)      strextend (&command, "-chiporderloop %s", ChipOrderLoopStr); 
+
     if (RESET_IMAGES)       strextend (&command, "-reset-images"); 
 
@@ -136,18 +173,6 @@
     if (LoopWeight2MASS) {  strextend (&command, "-loop-weights-2mass %s", LoopWeight2MASSstr); }
     if (LoopWeightTycho) {  strextend (&command, "-loop-weights-tycho %s", LoopWeightTychostr); }
-
-    strextend (&command, "-D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
-    strextend (&command, "-D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
-    strextend (&command, "-D RELASTRO_DPOS_MAX %f", DPOS_MAX);
-    strextend (&command, "-D ADDSTAR_RADIUS %f", ADDSTAR_RADIUS);
-
-    strextend (&command, "-D USE_GALAXY_MODEL %d", USE_GALAXY_MODEL);
-
-    strextend (&command, "-D USE_ICRF_CORRECT %d", USE_ICRF_CORRECT);
-    strextend (&command, "-D USE_ICRF_LOCAL %d",   USE_ICRF_LOCAL);
-    strextend (&command, "-D USE_ICRF_SHFIT %d",   USE_ICRF_SHFIT);
-    strextend (&command, "-D USE_ICRF_POLE %d",    USE_ICRF_POLE);
-
-    if (USE_FIXED_PIXCOORDS) strextend (&command, "-D USE_FIXED_PIXCOORDS 1");
+    if (LoopWeightGAIA)  {  strextend (&command, "-loop-weights-gaia %s", LoopWeightGAIAstr); }
+    if (APPLY_PROPER_MOTION) strextend (&command, "-apply-proper-motion");
 
     if (TimeSelect) { 
Index: trunk/Ohana/src/relastro/src/load_catalogs.c
===================================================================
--- trunk/Ohana/src/relastro/src/load_catalogs.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/load_catalogs.c	(revision 39926)
@@ -178,37 +178,34 @@
     strextend (&command, "relastro_client -load-objects %s", table->hosts[i].results);
     strextend (&command, " -hostID %d", table->hosts[i].hostID);
+    strextend (&command, " -hostdir %s", table->hosts[i].pathname);
+
     strextend (&command, " -D CATDIR %s", CATDIR);
-    strextend (&command, " -hostdir %s", table->hosts[i].pathname);
     strextend (&command, " -region %f %f %f %f", UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax);
     strextend (&command, " -statmode %s", STATMODE);
     strextend (&command, " -minerror %f", MIN_ERROR);
+
     strextend (&command, " -D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
+    strextend (&command, " -D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
+
     strextend (&command, " -D RELASTRO_MIN_DISTANCE_MOD %f",     MIN_DISTANCE_MOD);
     strextend (&command, " -D RELASTRO_MAX_DISTANCE_MOD %f",     MAX_DISTANCE_MOD);
     strextend (&command, " -D RELASTRO_MAX_DISTANCE_MOD_ERR %f", MAX_DISTANCE_MOD_ERR);
 
+    strextend (&command, "-D USE_GALAXY_MODEL %d", USE_GALAXY_MODEL);
+    strextend (&command, "-D USE_ICRF_CORRECT %d", USE_ICRF_CORRECT);
+
     if (FIT_MODE == FIT_PM_ONLY)  	 strextend (&command, "-pm");
     if (FIT_MODE == FIT_PAR_ONLY) 	 strextend (&command, "-par");
     if (FIT_MODE == FIT_PM_AND_PAR)      strextend (&command, "-pmpar");
 
-    if (VERBOSE)       strextend (&command, "-v");
-    if (VERBOSE2)      strextend (&command, "-vv");
-    if (RESET)         strextend (&command, "-reset");
-    if (ImagSelect)    strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
-    if (MaxDensityUse) strextend (&command, "-max-density %f", MaxDensityValue);
-    if (FlagOutlier)   strextend (&command, "-clip %d", CLIP_THRESH);
-    if (ExcludeBogus)  strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
-
-    if (USE_ICRF_CORRECT) strextend (&command, "-D USE_ICRF_CORRECT %d", USE_ICRF_CORRECT);
-    if (USE_GALAXY_MODEL) strextend (&command, "-D USE_GALAXY_MODEL %d", USE_GALAXY_MODEL);
-    
-    if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
-      strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
-    }
-    if (DCR_RED_COLOR_POS && DCR_RED_COLOR_NEG) {
-      strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
-    }
-
-    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
+    if (VERBOSE)             strextend (&command, "-v");
+    if (VERBOSE2)            strextend (&command, "-vv");
+    if (RESET)               strextend (&command, "-reset");
+		             
+    if (ImagSelect)          strextend (&command, "-instmag %f %f", ImagMin, ImagMax);
+    if (MaxDensityUse)       strextend (&command, "-max-density %f", MaxDensityValue);
+    if (FlagOutlier)         strextend (&command, "-clip %d", CLIP_THRESH);
+    if (ExcludeBogus)        strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
+
     if (USE_FIXED_PIXCOORDS) strextend (&command, "-D USE_FIXED_PIXCOORDS 1");
     if (PHOTCODE_KEEP_LIST)  strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST);
@@ -217,4 +214,19 @@
     if (PhotFlagBad)         strextend (&command, "+photflagbad %d", PhotFlagBad); 
     if (PhotFlagPoor)        strextend (&command, "+photflagpoor %d", PhotFlagPoor);
+
+    if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
+      strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
+    }
+    if (DCR_RED_COLOR_POS && DCR_RED_COLOR_NEG) {
+      strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
+    }
+
+    if (SKIP_PS1_CHIP)       strextend (&command, "-skip-ps1-chip");
+    if (SKIP_PS1_STACK)      strextend (&command, "-skip-ps1-stack");
+    if (SKIP_HSC)            strextend (&command, "-skip-hsc");
+    if (SKIP_CFH)            strextend (&command, "-skip-cfh");
+
+    if (USE_ALL_IMAGES)      strextend (&command, "-use-all-images");
+
     // XXX note that the above pass in the flag as decimal -- also note that args.c cannot handle 0xHEX values
 
@@ -282,4 +294,6 @@
   CatalogSplitter *catalogs = BrightCatalogSplitInit (Nsecfilt);
 
+  ohana_memstats (TRUE);
+
   for (i = 0; i < table->Nhosts; i++) {
 
@@ -296,4 +310,6 @@
     free (bcatalog->secfilt);
     free (bcatalog);
+
+    ohana_memstats (TRUE);
   }
 
@@ -320,4 +336,5 @@
 
   BrightCatalogSplitFree (catalogs);
+  ohana_memstats (TRUE);
 
   return (catalog);
Index: trunk/Ohana/src/relastro/src/load_images.c
===================================================================
--- trunk/Ohana/src/relastro/src/load_images.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/load_images.c	(revision 39926)
@@ -66,5 +66,5 @@
   }
 
-  initImages (subset, LineNumber, Nsubset);
+  initImages (subset, LineNumber, Nsubset, !USE_ALL_IMAGES);
   MARKTIME("  init images: %f sec\n", dtime);
   
Index: trunk/Ohana/src/relastro/src/relastro_images.c
===================================================================
--- trunk/Ohana/src/relastro/src/relastro_images.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/relastro_images.c	(revision 39926)
@@ -16,4 +16,7 @@
   int finalPassMode = FIT_MODE; // start with the globally-defined fit mode
   FIT_MODE = FIT_AVERAGE;
+
+  int RESET_ON_UPDATE = RESET;  
+  RESET = TRUE; // we need to reset when we load the bright catalog subset 
 
   /* lock and load the image db table */
@@ -65,4 +68,6 @@
   // XXX NOTE : for 2mass reset, photcodesKeep should now limit to 2MASS measurements
 
+  USE_IRLS = FALSE;  // do not use IRLS yet -- leads to excessive outlier rejections in the loops
+
   /* major modes */
   switch (FIT_TARGET) {
@@ -90,4 +95,11 @@
       break;
 
+    case SET_CHIPS:
+      // we just want to fit the selected chips to the mean positions
+      UpdateChips (catalog, Ncatalog, 0);   // measure.X,Y -> R,D, fit image.coords
+      MARKTIME("update chips: %f sec\n", dtime);
+
+      break;
+
     case TARGET_MOSAICS:
       for (i = 0; i < NLOOP; i++) {
@@ -102,12 +114,4 @@
   }
 
-  if (!UPDATE) { 
-    freeStarMaps();
-    gfits_db_free (&db);
-    ohana_memcheck (VERBOSE);
-    ohana_memdump (VERBOSE);
-    exit (0);
-  }
-
   // free the image / measurement pointers
   freeImageBins (Ncatalog);
@@ -117,4 +121,12 @@
   free (catalog);
   freeMosaics ();
+
+  if (!UPDATE) { 
+    freeStarMaps();
+    dvo_image_unlock (&db); 
+    freeImages (db.ftable.buffer);
+    gfits_db_free (&db);
+    return TRUE;
+  }
 
   // If we did NOT use all images, then we applied the measured corrections to a subset of
@@ -154,4 +166,6 @@
   // iterate over catalogs to make detection coordinates consistant
   if (APPLY_OFFSETS) {
+    USE_IRLS = ALLOW_IRLS;  // now that we have fitted the images, choose the user's option
+    RESET = RESET_ON_UPDATE;
     UpdateObjectOffsets (skylist, 0, NULL);
   }
Index: trunk/Ohana/src/relastro/src/relastro_objects.c
===================================================================
--- trunk/Ohana/src/relastro/src/relastro_objects.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/relastro_objects.c	(revision 39926)
@@ -159,8 +159,13 @@
     strextend (&command, "relastro_client -update-objects");
     strextend (&command, "-hostID %d", table->hosts[i].hostID);
+    strextend (&command, "-hostdir %s", table->hosts[i].pathname);
+
     strextend (&command, "-D CATDIR %s", CATDIR);
-    strextend (&command, "-hostdir %s", table->hosts[i].pathname);
     strextend (&command, "-region %f %f %f %f", UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax);
     strextend (&command, "-statmode %s", STATMODE);
+    strextend (&command, "-minerror %f", MIN_ERROR);
+
+    strextend (&command, "-D RELASTRO_SIGMA_LIM %f", SIGMA_LIM);
+    strextend (&command, "-D RELASTRO_SRC_MEAS_TOOFEW %d", SRC_MEAS_TOOFEW);
 
     if (FIT_MODE == FIT_PM_ONLY)  	 { strextend (&command, "-pm"); }
@@ -171,10 +176,10 @@
     if (VERBOSE2)      { strextend (&command, "-vv"); }
     if (RESET)         { strextend (&command, "-reset"); }
-    if (UPDATE)        { strextend (&command, "-update"); }
+
     if (ImagSelect)    { strextend (&command, "-instmag %f %f", ImagMin, ImagMax); }
     if (MaxDensityUse) { strextend (&command, "-max-density %f", MaxDensityValue); }
     if (FlagOutlier)   { strextend (&command, "-clip %d", CLIP_THRESH); }
-
-    if (USE_ALL_IMAGES)      { strextend (&command, "-use-all-images"); }
+    if (ExcludeBogus)    strextend (&command, "-exclude-bogus %f", ExcludeBogusRadius);
+
     if (USE_FIXED_PIXCOORDS) { strextend (&command, "-D USE_FIXED_PIXCOORDS 1"); }
     if (PHOTCODE_KEEP_LIST)  { strextend (&command, "+photcode %s", PHOTCODE_KEEP_LIST); }
@@ -185,4 +190,14 @@
     // XXX note that the above pass in the flag as decimal -- also note that args.c cannot handle 0xHEX values
 
+    if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
+      strextend (&command, "-dcr-blue-color %s %s", DCR_BLUE_COLOR_POS, DCR_BLUE_COLOR_NEG); 
+    }
+    if (DCR_RED_COLOR_POS && DCR_RED_COLOR_NEG) {
+      strextend (&command, "-dcr-red-color %s %s", DCR_RED_COLOR_POS, DCR_RED_COLOR_NEG); 
+    }
+
+    if (UPDATE)        { strextend (&command, "-update"); }
+    if (USE_ALL_IMAGES)      { strextend (&command, "-use-all-images"); }
+
     if (MinBadQF > 0.0)          strextend (&command, "-min-bad-psfqf %f", MinBadQF); 
     if (MaxMeanOffset != 10.0)   strextend (&command, "-max-mean-offset  %f", MaxMeanOffset); 
Index: trunk/Ohana/src/relastro/src/relastro_parallel_images.c
===================================================================
--- trunk/Ohana/src/relastro/src/relastro_parallel_images.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/relastro_parallel_images.c	(revision 39926)
@@ -61,5 +61,5 @@
   initMosaics (image, Nimage);
 
-  initImages (image, NULL, Nimage);
+  initImages (image, NULL, Nimage, FALSE);
 
   SkyTable *sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
@@ -103,4 +103,8 @@
 
   client_logger_message ("starting the loops: %s\n", myHostName);
+
+  RESET = TRUE; // we need to reset when we load the bright catalog subset 
+  FIT_MODE = FIT_AVERAGE; // we need to only fit the average
+  USE_IRLS = FALSE;  // do not use IRLS yet -- leads to excessive outlier rejections in the loops
 
   /* major modes */
Index: trunk/Ohana/src/relastro/src/select_images.c
===================================================================
--- trunk/Ohana/src/relastro/src/select_images.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/select_images.c	(revision 39926)
@@ -121,4 +121,10 @@
     }
 
+    // allow certain cameras to stay static
+    if (SKIP_PS1_CHIP  && isGPC1chip (timage[i].photcode)) continue;
+    if (SKIP_PS1_STACK && isGPC1stack(timage[i].photcode)) continue;
+    if (SKIP_HSC       && isHSCchip  (timage[i].photcode)) continue;
+    if (SKIP_CFH       && isCFHchip  (timage[i].photcode)) continue;
+    
     /* select images by photcode, or equiv photcode, if specified */
     if (NphotcodesKeep > 0) {
@@ -187,4 +193,6 @@
     if (DmaxImage < DminSkyRegion) continue;
     
+    if (KEEP_ALL_IMAGES_RA) goto found_it;
+
     // the sky region RA is defined to be 0 - 360.0
     if (RminImage > RmaxSkyRegion) continue;
Index: trunk/Ohana/src/relastro/src/syncfile.c
===================================================================
--- trunk/Ohana/src/relastro/src/syncfile.c	(revision 39693)
+++ trunk/Ohana/src/relastro/src/syncfile.c	(revision 39926)
@@ -39,4 +39,5 @@
     int loop;
     sscanf (message, "%*s %d", &loop);
+    if (CATCH_UP && (nloop < loop)) return TRUE; // if I am behind this machine, I need to catch up!
     if (loop != nloop) {
       usleep (2000000);
Index: trunk/Ohana/src/relphot/include/relphot.h
===================================================================
--- trunk/Ohana/src/relphot/include/relphot.h	(revision 39693)
+++ trunk/Ohana/src/relphot/include/relphot.h	(revision 39926)
@@ -309,4 +309,5 @@
 int    RESET_ZEROPTS;
 int    REPAIR_WARPS;
+int    PRESERVE_PS1;
 int    UPDATE;
 int    SAVE_IMAGE_UPDATES;
@@ -616,4 +617,7 @@
 int isTYCHO (int photcode);
 
+int isHSCchip  (int photcode);
+int isCFHchip  (int photcode);
+
 int magStatsByRanking (StatDataSet *dataset, StatType *stats);
 
Index: trunk/Ohana/src/relphot/src/args.c
===================================================================
--- trunk/Ohana/src/relphot/src/args.c	(revision 39693)
+++ trunk/Ohana/src/relphot/src/args.c	(revision 39926)
@@ -226,4 +226,10 @@
     remove_argument (N, &argc, argv);
     REPAIR_WARPS = TRUE;
+  }
+
+  PRESERVE_PS1 = FALSE;
+  if ((N = get_argument (argc, argv, "-preserve-ps1"))) {
+    remove_argument (N, &argc, argv);
+    PRESERVE_PS1 = TRUE;
   }
 
@@ -672,4 +678,10 @@
   }
 
+  PRESERVE_PS1 = FALSE;
+  if ((N = get_argument (argc, argv, "-preserve-ps1"))) {
+    remove_argument (N, &argc, argv);
+    PRESERVE_PS1 = TRUE;
+  }
+
   REPAIR_WARPS = FALSE;
   if ((N = get_argument (argc, argv, "-repair-warps"))) {
Index: trunk/Ohana/src/relphot/src/extra.c
===================================================================
--- trunk/Ohana/src/relphot/src/extra.c	(revision 39693)
+++ trunk/Ohana/src/relphot/src/extra.c	(revision 39926)
@@ -2,7 +2,8 @@
 
 // for now (20140710) I need to identify gpc1 chips explicitly.  generalize in the future
+// note that the 4000, 14000, 15000 sets are SIMTEST (*not* synthetic) 
 int whichGPC1filter (int photcode) {
 
-  if (((photcode > 10000) && (photcode < 10077)) || (photcode == 4100)) return PS1_g; // g-band
+  if (((photcode > 10000) && (photcode < 10077)) || (photcode == 4100)) return PS1_g; // g-band 
   if (((photcode > 10100) && (photcode < 10177)) || (photcode == 4200)) return PS1_r; // r-band
   if (((photcode > 10200) && (photcode < 10277)) || (photcode == 4300)) return PS1_i; // i-band
@@ -83,2 +84,26 @@
 }
 
+// for now (20160925) I need to identify HSC chips explicitly.  generalize in the future
+int isHSCchip (int photcode) {
+
+  if ((photcode >= 20000) && (photcode <= 20111)) return TRUE; // g-band
+  if ((photcode >= 21000) && (photcode <= 21111)) return TRUE; // r-band
+  if ((photcode >= 22000) && (photcode <= 22111)) return TRUE; // i-band
+  if ((photcode >= 23000) && (photcode <= 23111)) return TRUE; // z-band
+  if ((photcode >= 24000) && (photcode <= 24111)) return TRUE; // y-band
+
+  return FALSE;
+}
+
+// for now (20160925) I need to identify CFH chips explicitly.  generalize in the future
+int isCFHchip (int photcode) {
+
+  if ((photcode >= 100) && (photcode <= 152)) return TRUE; // g-band
+  if ((photcode >= 200) && (photcode <= 252)) return TRUE; // r-band
+  if ((photcode >= 300) && (photcode <= 352)) return TRUE; // i-band
+  if ((photcode >= 400) && (photcode <= 452)) return TRUE; // z-band
+  if ((photcode >= 500) && (photcode <= 552)) return TRUE; // y-band
+
+  return FALSE;
+}
+
Index: trunk/Ohana/src/relphot/src/reload_catalogs.c
===================================================================
--- trunk/Ohana/src/relphot/src/reload_catalogs.c	(revision 39693)
+++ trunk/Ohana/src/relphot/src/reload_catalogs.c	(revision 39926)
@@ -239,4 +239,5 @@
     if (RESET)             { strextend (&command, "-reset"); }
     if (RESET_ZEROPTS)     { strextend (&command, "-reset-zpts"); }
+    if (PRESERVE_PS1)      { strextend (&command, "-preserve-ps1"); }
     if (UPDATE)            { strextend (&command, "-update"); }
     if (IS_DIFF_DB)        { strextend (&command, "-is-diff-db"); }
Index: trunk/Ohana/src/relphot/src/relphot_objects.c
===================================================================
--- trunk/Ohana/src/relphot/src/relphot_objects.c	(revision 39693)
+++ trunk/Ohana/src/relphot/src/relphot_objects.c	(revision 39926)
@@ -243,4 +243,5 @@
     if (RESET_ZEROPTS) 	   { strextend (&command, "-reset-zpts"); }
     if (REPAIR_WARPS)      { strextend (&command, "-repair-warps"); }
+    if (PRESERVE_PS1)      { strextend (&command, "-preserve-ps1"); }
     if (IS_DIFF_DB)        { strextend (&command, "-is-diff-db"); }
     if (UPDATE)        	   { strextend (&command, "-update"); }
Index: trunk/Ohana/src/relphot/src/setMrelCatalog.c
===================================================================
--- trunk/Ohana/src/relphot/src/setMrelCatalog.c	(revision 39693)
+++ trunk/Ohana/src/relphot/src/setMrelCatalog.c	(revision 39926)
@@ -142,4 +142,6 @@
   int Galaxy2MASS = FALSE;
   int haveTYCHO = FALSE;
+  int haveHSC = FALSE;
+  int haveCFH = FALSE;
 
   float stargalmax = 0.0;
@@ -163,4 +165,6 @@
     
     if (isTYCHO(measureT[k].photcode)) { haveTYCHO = TRUE; }
+    if (isHSCchip(measureT[k].photcode)) { haveHSC = TRUE; }
+    if (isCFHchip(measureT[k].photcode)) { haveCFH = TRUE; }
 
     if (is2MASS(measureT[k].photcode)) {
@@ -317,5 +321,22 @@
   // now calculate the mean stats for the Nsec bands.
   for (Nsec = 0; Nsec < Nsecfilt; Nsec++) {
-    dvo_secfilt_init (&secfilt[Nsec], SECFILT_RESET_CHIP); // this does not reset astrometry or STACK bits
+
+    // if we detected this object in PS1, or do not request -preserve-ps1, keep the mean photometry values
+    if (!PRESERVE_PS1 || !(secfilt[Nsec].flags & ID_SECF_HAS_PS1)) {
+      dvo_secfilt_init (&secfilt[Nsec], SECFILT_RESET_CHIP); // this does not reset astrometry or STACK bits
+    }
+
+    if (haveTYCHO) {
+      secfilt[Nsec].flags |= ID_SECF_HAS_TYCHO;
+    }
+    if (haveHSC) {
+      secfilt[Nsec].flags |= ID_SECF_HAS_HSC;
+    }
+    if (haveCFH) {
+      secfilt[Nsec].flags |= ID_SECF_HAS_CFH;
+    }
+
+    if (PRESERVE_PS1 && (secfilt[Nsec].flags & ID_SECF_HAS_PS1)) continue;
+    // if -preserve-ps1 is set and this object has PS1 data, skip the rest of the steps:
 
     // XXX hardwired grizy = (01234) JHK = (567) w = (8)
@@ -324,8 +345,4 @@
     } else {
       secfilt[Nsec].Ncode = results->Nmeas[Nsec]; // 2MASS data if it exists
-    }
-
-    if (haveTYCHO) {
-      secfilt[Nsec].flags |= ID_SECF_HAS_TYCHO;
     }
 
Index: trunk/Ohana/src/uniphot/include/setgalmodel.h
===================================================================
--- trunk/Ohana/src/uniphot/include/setgalmodel.h	(revision 39693)
+++ trunk/Ohana/src/uniphot/include/setgalmodel.h	(revision 39926)
@@ -10,5 +10,4 @@
 char        *HOSTDIR;
 int          VERBOSE;
-int          TESTING;
 int          UPDATE;
 int          PARALLEL;
@@ -18,4 +17,6 @@
 char        *SINGLE_CPT;
 
+float        TEST_SCALE;
+char        *GALAXY_MODEL;
 SkyRegion    UserPatch;
 
Index: trunk/Ohana/src/uniphot/include/setphot.h
===================================================================
--- trunk/Ohana/src/uniphot/include/setphot.h	(revision 39693)
+++ trunk/Ohana/src/uniphot/include/setphot.h	(revision 39926)
@@ -67,4 +67,6 @@
 int          VERBOSE;
 int          RESET;
+int          PHOTCODE_MIN;
+int          PHOTCODE_MAX;
 int          UBERCAL; // load the supplied ubercal zero point fits table (with flat-field corrections)
 int          NO_METADATA; // the supplied ubercal data has no descriptive metadata
Index: trunk/Ohana/src/uniphot/src/initialize_setgalmodel.c
===================================================================
--- trunk/Ohana/src/uniphot/src/initialize_setgalmodel.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/initialize_setgalmodel.c	(revision 39926)
@@ -45,6 +45,6 @@
 
   // XXX add to config?
-  if (!InitGalaxyModel ("FEAST-HIPPARCOS")) {
-    fprintf (stderr, "failed to init galaxy model\n");
+  if (!InitGalaxyModel (GALAXY_MODEL)) {
+    fprintf (stderr, "failed to init galaxy model %s\n", GALAXY_MODEL);
     exit (2);
   }
@@ -92,7 +92,16 @@
   }
 
-  TESTING = FALSE;
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (argc, argv, "-galaxy-model"))) {
+    remove_argument (N, &argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("FEAST-HIPPARCOS");
+
+  TEST_SCALE = 1.0;
   if ((N = get_argument (argc, argv, "-testing"))) {
-    TESTING = TRUE;
+    remove_argument (N, &argc, argv);
+    TEST_SCALE = atof(argv[N]);
     remove_argument (N, &argc, argv);
   }
@@ -171,6 +180,6 @@
   }
 
-  // XXX add to config?
-  if (!InitGalaxyModel ("ROESER")) {
+  // from args
+  if (!InitGalaxyModel (GALAXY_MODEL)) {
     fprintf (stderr, "failed to init galaxy model\n");
     exit (2);
@@ -212,7 +221,16 @@
   }
 
-  TESTING = FALSE;
+  GALAXY_MODEL = NULL;
+  if ((N = get_argument (argc, argv, "-galaxy-model"))) {
+    remove_argument (N, &argc, argv);
+    GALAXY_MODEL = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GALAXY_MODEL) GALAXY_MODEL = strcreate ("FEAST-HIPPARCOS");
+
+  TEST_SCALE = 1.0;
   if ((N = get_argument (argc, argv, "-testing"))) {
-    TESTING = TRUE;
+    remove_argument (N, &argc, argv);
+    TEST_SCALE = atof(argv[N]);
     remove_argument (N, &argc, argv);
   }
Index: trunk/Ohana/src/uniphot/src/initialize_setphot.c
===================================================================
--- trunk/Ohana/src/uniphot/src/initialize_setphot.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/initialize_setphot.c	(revision 39926)
@@ -109,4 +109,14 @@
   if ((N = get_argument (argc, argv, "-reset"))) {
     RESET = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  PHOTCODE_MIN = 0;
+  PHOTCODE_MAX = 0;
+  if ((N = get_argument (argc, argv, "-photcode-range"))) {
+    remove_argument (N, &argc, argv);
+    PHOTCODE_MIN = atoi (argv[N]);    
+    remove_argument (N, &argc, argv);
+    PHOTCODE_MAX = atoi (argv[N]);    
     remove_argument (N, &argc, argv);
   }
Index: trunk/Ohana/src/uniphot/src/initialize_setphot_client.c
===================================================================
--- trunk/Ohana/src/uniphot/src/initialize_setphot_client.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/initialize_setphot_client.c	(revision 39926)
@@ -96,4 +96,14 @@
   }
 
+  PHOTCODE_MIN = 0;
+  PHOTCODE_MAX = 0;
+  if ((N = get_argument (argc, argv, "-photcode-range"))) {
+    remove_argument (N, &argc, argv);
+    PHOTCODE_MIN = atoi (argv[N]);    
+    remove_argument (N, &argc, argv);
+    PHOTCODE_MAX = atoi (argv[N]);    
+    remove_argument (N, &argc, argv);
+  }
+
   // region of interest
   UserPatch.Rmin = 0;
Index: trunk/Ohana/src/uniphot/src/update_catalog_setgalmodel.c
===================================================================
--- trunk/Ohana/src/uniphot/src/update_catalog_setgalmodel.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/update_catalog_setgalmodel.c	(revision 39926)
@@ -33,7 +33,13 @@
 
     // fake or real QSOs are marked with FeH = +/- 100.0
-    if (fabs(starpar->FeH) > 99.0) continue;
+    if (fabs(starpar->FeH) > 99.0) { 
+      starpar->uRA  = 0.0;
+      starpar->uDEC = 0.0;
+      average[i].uRgal = 0.0;
+      average[i].uDgal = 0.0;
+      continue;
+    }
 
-    // NOTE: distance is in kiloparsec
+    // NOTE: DistMag is standard (10pc reference).  SolarMotionModel wants distance in kiloparsec:
     double distance = pow(10.0, 0.2*(starpar->DistMag + 5.0)) / 1000.0;
 
@@ -51,8 +57,6 @@
 
     // XXX: amplify motion to make tests easier:
-    if (TESTING) {
-      uL *= 100.0;
-      uB *= 100.0;
-    }
+    uL *= TEST_SCALE;
+    uB *= TEST_SCALE;
     
     double uR, uD;
Index: trunk/Ohana/src/uniphot/src/update_catalog_setphot.c
===================================================================
--- trunk/Ohana/src/uniphot/src/update_catalog_setphot.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/update_catalog_setphot.c	(revision 39926)
@@ -1,3 +1,7 @@
 # include "setphot.h"
+
+// XXX I need to add a few things for HSC + MC + GPC1:
+// * I can generate a zpt table for the MC exposures using the nominal zero points
+// * for the HSC data, I need to add a function to define Mflat as a function of Xmos, Ymos
 
 void update_catalog_setphot (Catalog *catalog, Image *image, off_t *index, off_t Nimage, CamPhotomCorrection *camcorr) {
@@ -14,8 +18,19 @@
     Measure *measure = &catalog[0].measure[i];
 
-    // only do GPC1 data for now
-    if (measure[0].photcode < 10000) continue;
-    if (measure[0].photcode > 10600) continue;
+    // XXX deprecated 2016.09.22 : only do GPC1 data for now
+    // if (measure[0].photcode < 10000) continue;
+    // if (measure[0].photcode > 10600) continue;
       
+    // only do DEP photcodes (skip REF, etc)
+    PhotCode *code = GetPhotcodebyCode (measure[0].photcode);
+    if (!code) continue; // invalid photcode
+    if (code->type != PHOT_DEP) continue;
+
+    // allow a restriction on the modified zpts:
+    if (PHOTCODE_MAX) {
+      if (measure[0].photcode < PHOTCODE_MIN) continue;
+      if (measure[0].photcode > PHOTCODE_MAX) continue;
+    }
+
     off_t idx = measure[0].imageID;
     if (idx <= 0) continue; // detections with imageID == 0 do not have a valid image (eg, ref photcode)
@@ -33,4 +48,16 @@
       Mflat = CamPhotomCorrectionValue (camcorr, flat_id, measure[0].Xccd, measure[0].Yccd);
     }
+
+# if (0)
+    // the mosaic lookup is broken : fix it then redo this block
+    if (radialZP) {
+      mosaic = MatchMosaicMetadata (measure[0].imageID);
+      if (mosaic == NULL) break;
+      double Rm = measure[0].R;
+      double Dm = measure[0].D;
+      RD_to_XY (&XMOS_MEAS, &YMOS_MEAS, Rm, Dm, mosaic);
+      Mflat = RadialZPtrend (XMOS_MEAS, XMOS_MEAS);
+    }
+# endif
 
     measure[0].Mcal = Mcal;
Index: trunk/Ohana/src/uniphot/src/update_dvo_setgalmodel.c
===================================================================
--- trunk/Ohana/src/uniphot/src/update_dvo_setgalmodel.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/update_dvo_setgalmodel.c	(revision 39926)
@@ -98,5 +98,5 @@
 
     if (VERBOSE)       	  { strextend (&command, "-v"); }
-    if (TESTING)       	  { strextend (&command, "-testing"); }
+    if (TEST_SCALE != 1.0){ strextend (&command, "-testing %f", TEST_SCALE); }
     if (UPDATE)        	  { strextend (&command, "-update"); }
     if (UPDATE_CATFORMAT) { strextend (&command, "-update-catformat %s", UPDATE_CATFORMAT); }
Index: trunk/Ohana/src/uniphot/src/update_dvo_setphot.c
===================================================================
--- trunk/Ohana/src/uniphot/src/update_dvo_setphot.c	(revision 39693)
+++ trunk/Ohana/src/uniphot/src/update_dvo_setphot.c	(revision 39926)
@@ -179,4 +179,6 @@
     if (DCR_RESET)     	  { strextend (&command, "-DCR-reset"); }
     if (CAM_RESET)     	  { strextend (&command, "-CAM-reset"); }
+
+    if (PHOTCODE_MAX) 	  { strextend (&command, "-photcode-range %d %d", PHOTCODE_MIN, PHOTCODE_MAX); }
 
     fprintf (stderr, "command: %s\n", command);
