Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/.dvo
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/.dvo	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/.dvo	(revision 21703)
@@ -0,0 +1,1 @@
+avextract -phothelp
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageOps.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageOps.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageOps.c	(revision 21703)
@@ -0,0 +1,77 @@
+# include "dvo1.h"
+
+void image_subset (Image *image, int Nimage, int **Subset, int *Nsubset,
+		   Graphdata *graph, int RegionSelect, 
+		   unsigned long int tzero, double trange, int TimeSelect) 
+{
+
+  int i, j, flipped, status, InPic;
+  int *subset;
+  int N, n, npts;
+  double r, d, X, Y, x[4], y[4], Rmin, Rmax, Rmid;
+
+  Rmin = Rmax = Rmid = 0;
+  if (RegionSelect) {
+    Rmin = graph[0].coords.crval1 - 182.0;
+    Rmax = graph[0].coords.crval1 + 182.0;
+    Rmid = 0.5*(Rmin + Rmax);
+    BuildChipMatch (image, Nimage);
+  }
+
+  if (trange < 0) {
+    tzero = tzero + trange;
+    trange = fabs (trange);
+  }
+
+  npts = 200;
+  ALLOCATE (subset, int, npts);
+  n = N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    if (RegionSelect) {
+      if (!FindMosaicForImage (image, Nimage, i)) continue;
+      /* project this image to screen display coords */
+      x[0] = 0;           y[0] = 0;
+      x[1] = image[i].NX; y[1] = 0;
+      x[2] = image[i].NX; y[2] = image[i].NY;
+      x[3] = 0;           y[3] = image[i].NY;
+      InPic = flipped = FALSE;
+      for (j = 0; j < 4; j++) {
+	XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+	/* use same side of 0,360 boundary for all corners */
+	if ((j == 0) && (r < Rmin)) flipped = TRUE; 
+	if ((j == 0) && (r > Rmax)) flipped = TRUE; 
+	while (flipped && (r < Rmid)) r+= 360.0;
+	while (flipped && (r > Rmid)) r-= 360.0;
+	status = RD_to_XY (&X, &Y, r, d, &graph[0].coords);
+	if (!status) continue;
+	if (X < graph[0].xmin) continue;
+	if (X > graph[0].xmax) continue;
+	if (Y < graph[0].ymin) continue;
+	if (Y > graph[0].ymax) continue;
+	goto in_region;
+	/** we miss any images which surround the region.  we are also
+	    missing the DIS images for which the corners don't touch
+	    the region, but which are needed for WRP images with
+	    corners touching the region **/
+      }
+      continue;
+    }
+  in_region:
+    subset[n] = i;
+    n++;
+    if (n > npts - 1) {
+      npts += 200;
+      REALLOCATE (subset, int, npts);
+    }
+  }
+
+  REALLOCATE (subset, int, MAX (n, 1));
+  *Subset = subset;
+  *Nsubset = n;
+  return;
+}
+
+/* this routine fills the subset index with the list of selected images.
+   images may be selected on the basis of the region or on a time range 
+*/
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageSelection.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageSelection.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ImageSelection.c	(revision 21703)
@@ -0,0 +1,85 @@
+# include "dvo1.h"
+
+/* db image table */
+static Image *image = NULL;
+static int *subset = NULL;
+static int Nimage = 0;
+static int Nsubset = 0;
+static Coords mosaic;
+
+/* load images based on parameters and region, etc */
+int SetImageSelection (int mode) {
+
+  int Ngraph;
+  Graphdata graphsky;
+  int RegionSelect, TimeSelect;
+  time_t tzero, tend;
+
+  image = NULL;
+  subset = NULL;
+  
+  RegionSelect = GetRegionSelection();
+  if (RegionSelect) {
+    Ngraph = 0;
+    if (!GetGraphData (&graphsky, NULL, &Ngraph)) {
+      fprintf (stderr, "region display not available\n");
+      return (FALSE);
+    }
+  }
+
+  TimeSelect = GetTimeSelection (&tzero, &tend);
+
+  switch (mode) {
+    case MEAS_XCCD:
+    case MEAS_YCCD:
+      break;
+    case MEAS_XMOSAIC: 
+    case MEAS_YMOSAIC:
+      /* mosaic defines a frame with 0,0 at the mosaic center, and 1 arcsec / pixel */
+      mosaic.crpix1 = mosaic.crpix2 = 0.0;
+      mosaic.cdelt1 = mosaic.cdelt2 = 1.0 / 3600;
+      mosaic.pc1_1  = mosaic.pc2_2  = 1.0;
+      mosaic.pc1_2  = mosaic.pc2_1  = 0.0;
+      mosaic.Npolyterms = 0;
+      strcpy (mosaic.ctype, "RA---SIN");
+      break;
+    default:
+      return (TRUE);
+  }
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+  image_subset (image, Nimage, &subset, &Nsubset, &graphsky, RegionSelect, tzero, (double) tend - tzero, TimeSelect);
+  sort_image_subset (image, subset, Nsubset);
+  return (TRUE);
+}
+
+/* free loaded images */
+void FreeImageSelection () {
+  if (image != NULL) free (image);
+  if (subset != NULL) free (subset);
+  image = NULL;
+  subset = NULL;
+  return;
+}
+
+Image *MatchImage (unsigned int time, short int source) { 
+
+  int m;
+
+  m = match_image_subset (image, subset, Nsubset, time, source);
+  if (m == -1) return (NULL);
+  if (!FindMosaicForImage (image, Nimage, m)) return (NULL);
+  return (&image[m]);
+}
+
+Coords *MatchMosaic (unsigned int time, short int source) { 
+
+  int m;
+
+  m = match_image_subset (image, subset, Nsubset, time, source);
+  if (m == -1) return (NULL);
+  mosaic.crval1 = image[m].coords.crval1;
+  mosaic.crval2 = image[m].coords.crval2;
+  return (&mosaic);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/LoadImages.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/LoadImages.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/LoadImages.c	(revision 21703)
@@ -0,0 +1,48 @@
+# include "dvo1.h"
+
+Image *LoadImages (int *nimage) {
+
+  char filename[256];
+  int Nimage, NIMAGE;
+  FILE *f;
+  Header header;
+  Image *image;
+  
+  VarConfig ("IMAGE_CATALOG", "%s", filename);
+
+  *nimage = 0;
+  NIMAGE = 0;
+  Nimage = 0;
+  image  = NULL;
+
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (filename, &header)) {
+    fprintf (stderr, "No available image catalog %s (1)\n", filename);
+    return (NULL);
+  }
+
+  fits_scan (&header, "NIMAGES", "%d", 1, &NIMAGE);
+  if (NIMAGE == 0) {
+    fprintf (stderr, "no images found\n");
+    return (NULL);
+  }
+
+  /* get ready to read data on images */ 
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "No available image catalog: %s (2)\n", filename);
+    free (header.buffer);
+    return (NULL);
+  }
+
+  ALLOCATE (image, Image, NIMAGE);
+  fseek (f, header.size, SEEK_SET); 
+  Nimage = Fread (image, sizeof(Image), NIMAGE, f, "image");
+  if (Nimage != NIMAGE) {
+    fprintf (stderr, "failed to read in all images (%d of %d)\n", Nimage, NIMAGE);
+  }
+
+  fclose (f);
+  *nimage = Nimage;
+  return (image);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/Makefile
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/Makefile	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/Makefile	(revision 21703)
@@ -0,0 +1,127 @@
+include ../../../Configure
+
+HOME    =       $(ROOT)/src/opihi
+BIN     =       $(HOME)/bin
+LIB     =       $(HOME)/lib
+INC     =       $(HOME)/include
+SDIR    =       $(HOME)/dvo
+#
+DESTBIN =       $(LBIN)
+DESTLIB =       $(LLIB)
+DESTINC =       $(LINC)
+DESTMAN =       $(LMAN)
+DESTHLP =       $(LHLP)/dvo
+#  
+INCS    =       -I$(INC) -I$(LINC) -I$(XINC)
+LFLAGS  =       -L$(LLIB) -L$(LIB)
+LIBS1   =       -lFITS -lsocket -lnsl -lreadline -ltermcap -lohana -lm
+LIBS2   =       -lbasiccmd -ldatacmd -lastrocmd -lshell -ldata 
+LIBS    =       $(LIBS2) $(LIBS1) 
+CFLAGS  =       $(INCS) -DHELPDIR_DEFAULT=$(DESTHLP)
+CCFLAGS =       $(LIBS) 
+
+# dvo user commands and support functions ########################
+
+funcs = \
+$(SDIR)/init.$(ARCH).o            	\
+$(SDIR)/ImageOps.$(ARCH).o		\
+$(SDIR)/ImageSelection.$(ARCH).o	\
+$(SDIR)/LoadImages.$(ARCH).o		\
+$(SDIR)/aregion.$(ARCH).o               \
+$(SDIR)/compare.$(ARCH).o               \
+$(SDIR)/find_regions.$(ARCH).o	  	\
+$(SDIR)/get_regions.$(ARCH).o           \
+$(SDIR)/match_image.$(ARCH).o		\
+$(SDIR)/photometry.$(ARCH).o            \
+$(SDIR)/dvomisc.$(ARCH).o		\
+$(SDIR)/region_list.$(ARCH).o		\
+$(SDIR)/dvo.$(ARCH).o
+
+cmds = \
+$(SDIR)/avextract.$(ARCH).o	  	\
+$(SDIR)/badimages.$(ARCH).o	  	\
+$(SDIR)/calextract.$(ARCH).o      	\
+$(SDIR)/calmextract.$(ARCH).o     	\
+$(SDIR)/catalog.$(ARCH).o	  	\
+$(SDIR)/ccd.$(ARCH).o             	\
+$(SDIR)/cmatch.$(ARCH).o	  	\
+$(SDIR)/cmd.$(ARCH).o             	\
+$(SDIR)/cmpload.$(ARCH).o	  	\
+$(SDIR)/cmpread.$(ARCH).o	  	\
+$(SDIR)/ddmags.$(ARCH).o	  	\
+$(SDIR)/detrend.$(ARCH).o	  	\
+$(SDIR)/dmagaves.$(ARCH).o	  	\
+$(SDIR)/dmagmeas.$(ARCH).o	  	\
+$(SDIR)/dmags.$(ARCH).o		  	\
+$(SDIR)/dmt.$(ARCH).o		  	\
+$(SDIR)/elixir.$(ARCH).o                \
+$(SDIR)/fitcolors.$(ARCH).o             \
+$(SDIR)/gcat.$(ARCH).o		  	\
+$(SDIR)/gimages.$(ARCH).o	  	\
+$(SDIR)/gstar.$(ARCH).o		  	\
+$(SDIR)/images.$(ARCH).o	  	\
+$(SDIR)/imbox.$(ARCH).o		  	\
+$(SDIR)/imdata.$(ARCH).o	  	\
+$(SDIR)/imdense.$(ARCH).o	  	\
+$(SDIR)/imextract.$(ARCH).o	  	\
+$(SDIR)/imlist.$(ARCH).o	  	\
+$(SDIR)/imphot.$(ARCH).o	  	\
+$(SDIR)/imrough.$(ARCH).o	  	\
+$(SDIR)/imsearch.$(ARCH).o	  	\
+$(SDIR)/imstats.$(ARCH).o	  	\
+$(SDIR)/lcat.$(ARCH).o		  	\
+$(SDIR)/lcurve.$(ARCH).o	  	\
+$(SDIR)/lightcurve.$(ARCH).o	  	\
+$(SDIR)/mextract.$(ARCH).o	  	\
+$(SDIR)/pcat.$(ARCH).o		  	\
+$(SDIR)/photcodes.$(ARCH).o	  	\
+$(SDIR)/pmeasure.$(ARCH).o	  	\
+$(SDIR)/procks.$(ARCH).o	  	\
+$(SDIR)/skycoverage.$(ARCH).o	  	\
+$(SDIR)/showtile.$(ARCH).o	  	\
+$(SDIR)/simage.$(ARCH).o	  	\
+$(SDIR)/subpix.$(ARCH).o  \
+$(SDIR)/version.$(ARCH).o
+
+libs = \
+$(DESTLIB)/libshell.a \
+$(DESTLIB)/libdata.a \
+$(DESTLIB)/libbasiccmd.a \
+$(DESTLIB)/libastrocmd.a \
+$(DESTLIB)/libdatacmd.a
+
+dvo: $(BIN)/dvo.$(ARCH)
+
+$(BIN)/dvo.$(ARCH) : $(funcs) $(cmds) $(libs)
+
+install: $(DESTBIN)/dvo help
+
+help: cmd.basic.help cmd.data.help cmd.astro.help dvo.help
+
+.PHONY: dvo
+
+include ../Makefile.Common
+
+# deprecated functions: verify & delete
+#$(SDIR)/abszero.$(ARCH).o \
+#$(SDIR)/cals.$(ARCH).o \
+#$(SDIR)/dumpmags.$(ARCH).o \
+#$(SDIR)/extract.$(ARCH).o \
+#$(SDIR)/gtypes.$(ARCH).o \
+#$(SDIR)/photresid.$(ARCH).o \
+#$(SDIR)/resid.$(ARCH).o \
+#$(SDIR)/zeropts.$(ARCH).o
+#$(SDIR)/objload.$(ARCH).o \ - make sure we have vect to tv
+#$(SDIR)/ccdextract.$(ARCH).o \
+#$(SDIR)/cmdextract.$(ARCH).o \
+#$(SDIR)/dmagextract.$(ARCH).o \
+#$(SDIR)/ddmagextract.$(ARCH).o \
+
+# future functions, not fully implemented
+#$(SDIR)/detrend.$(ARCH).o \
+#$(SDIR)/getxtra.$(ARCH).o \
+#$(SDIR)/addxtra.$(ARCH).o \
+
+# functions that need to be updated
+#$(SDIR)/gregions.$(ARCH).o \
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/addxtra.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/addxtra.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/addxtra.c	(revision 21703)
@@ -0,0 +1,60 @@
+# include "dvo1.h"
+
+typedef struct {
+  char type[64];
+  char name[64];
+  char source[256];
+  char mode[64];
+  char value[64];
+  char range[64];
+  double R, D;
+  int averef;
+} Xtras;
+
+int addxtra (int argc, char **argv) {
+  
+  Source = (char *) NULL;
+  if (N = get_argument (argc, argv, "-source")) {
+    remove_argument (N, &argc, argv);
+    Source = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Name = (char *) NULL;
+  if (N = get_argument (argc, argv, "-name")) {
+    remove_argument (N, &argc, argv);
+    Name = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Mode = (char *) NULL;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    Mode = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Range = (char *) NULL;
+  if (N = get_argument (argc, argv, "-range")) {
+    remove_argument (N, &argc, argv);
+    Range = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: addxtra R D radius (type) (value)\n");
+    return (FALSE);
+  }
+  
+  /*
+
+  validate the input values (type, defines the needed options)
+  find catalog (based on r,d)
+  load catalog (need to load measures?)
+  find the object
+  find the xtra entry (sorted by ra/dec? sorted by averef?)
+  add new entry
+  save catalog 
+  */
+}
+
+/* 
+  addxtra R D dR type value -name (name) -source (source) -mode (mode) -range (range) 
+*/
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/aregion.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/aregion.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/aregion.c	(revision 21703)
@@ -0,0 +1,81 @@
+# include "dvo1.h"
+# include "hstgsc.h"
+
+/* find region file which contains ra, dec */
+void aregion (GSCRegion *region, FILE *f, double ra, double dec, char *path) {
+  
+  char buffer[28800], temp[50], file[50];
+  double RA0, RA1, DEC0, DEC1;
+  int i, NBigDec, NLINES, done;
+  
+  while (ra < 0) { ra += 360.0; }
+  while (ra >= 360.0) { ra -= 360.0; }
+
+  if (dec >= 86.25) {
+    sprintf (file, "%s/n8230/pole.cpt", path);
+    region[0].DEC[0] = 86.25;
+    region[0].DEC[1] = 93.75;
+    region[0].RA[0] =  0.0;
+    region[0].RA[1] =  360.0;
+    strcpy (region[0].filename, file);
+    return;
+  }
+    
+  NBigDec = -1;
+  for (i = 0; i < 12; i++) {
+    if ((dec >= BigDecBounds[i]) && (dec < BigDecBounds[i+1])) {
+      NBigDec = i;
+      break;
+    }
+  }
+  if (NBigDec < 0) {
+    for (i = 13; i < 24; i++) {
+      if ((dec < BigDecBounds[i]) && (dec >= BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "dec out of range: %f\n", dec);
+  }
+    
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      
+  done = FALSE;
+  Fread (buffer, 1, 48*NDecLines[NBigDec], f, "char");
+  for (i = 0; !done && (i < NDecLines[NBigDec]); i++) {
+    strncpy (temp, &buffer[i*48], 48);
+    temp[49] = 0;
+    hstgsc_hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+    if (RA1 < RA0) RA1 += 360.0;
+    if ((dec >= 0) && (dec >= DEC0) && (dec < DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+    if ((dec < 0) && (dec < DEC0) && (dec >= DEC1) && (ra >= RA0) && (ra < RA1)) {
+      done = TRUE;
+    }
+  }
+
+  if (!done) {
+    fprintf (stderr, "error in search: %f %f\n", ra, dec);
+    exit (0);
+  }
+  temp[5] = 0;
+  sprintf (file, "%s/%s/%s.cpt", path, Dec2Sections[NBigDec],&temp[1]);
+  if (DEC0 < DEC1) {
+    region[0].DEC[0] = DEC0;
+    region[0].DEC[1] = DEC1;
+  } else {
+    region[0].DEC[0] = DEC1;
+    region[0].DEC[1] = DEC0;
+  }     
+  region[0].RA[0] = RA0;
+  region[0].RA[1] = RA1;
+  strcpy (region[0].filename, file);
+  return;
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/avextract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/avextract.c	(revision 21703)
@@ -0,0 +1,106 @@
+# include "dvo1.h"
+
+int avextract (int argc, char **argv) {
+  
+  int i, j, m, N, NPTS, param;
+  int Nsec, Nregions, mode;
+  char filename[256], catdir[256], *RegionName, *RegionList, *p;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code;
+  Vector *vec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  code = NULL;
+  mode = MAG_AVE;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  SetSelectionParam (0);
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 1)) goto usage;
+
+  /* interpret required command-line arguments: mextract (value) */
+  if (argc != 2) { goto usage; }
+  param = GetAverageParam (argv[1]);
+  if (param == AVE_ZERO) {
+    if (!GetPhotcodeInfo (argv[1], &code, &mode)) {
+      GetAverageParamHelp ();
+      goto escape;
+    }
+    param = AVE_MAG;
+    for (p = argv[1]; *p != 0; p++) { 
+      if (*p == '.') *p = ':';
+    }
+  } 
+  if (!TestPhotSelections (&code, &mode, param)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* create storage vector */
+  N = 0;
+  NPTS = 1;
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  for (i = 0; i < Nregions; i++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (j = 0; j < catalog.Naverage; j++) {
+      m = catalog.average[j].offset;
+      vec[0].elements[N] = ExtractAverages (code, mode, &catalog.average[j], &catalog.secfilt[j*Nsec], &catalog.measure[m], param);
+      N++;
+      CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 2000);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+
+  if (regions != NULL) free (regions);
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: avextract (value) [options]\n");
+  fprintf (stderr, "  value: average.parameter or photcode\n");
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/badimages.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/badimages.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/badimages.c	(revision 21703)
@@ -0,0 +1,103 @@
+# include "dvo1.h"
+
+static int badim_int = FALSE;
+void badim_escape () {
+  badim_int = TRUE;
+}
+
+int badimages (int argc, char **argv) {
+  
+  FILE *f;
+  int i, Nimage, nimage, entry, First, Cross;
+  float *ptr;
+  double nominal, big, small, value;
+  Header header;
+  Image *image;
+  char ImageCat[256];
+
+  VarConfig ("IMAGE_CATALOG", "%s", ImageCat);
+  
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: badimages entry value\n");
+    fprintf (stderr, "   OR: badimages -image N\n");
+    return (FALSE);
+  }
+  
+  Cross = FALSE;
+  First = FALSE;
+  nominal = 1;
+  if (!strcmp (argv[1], "-image")) {
+    First = TRUE;
+    entry = atof(argv[2]);
+  } else {
+    entry = atof(argv[1]);
+    nominal = atof(argv[2]);
+    if (!strcasecmp (argv[1], "x")) {
+      Cross = TRUE;
+    }
+  }
+  
+  /* check if image datafile exists, get header */
+  if (!fits_read_header (ImageCat, &header)) {
+    fprintf (stderr, "can't open image catalog %s\n", ImageCat);
+    return (FALSE);
+  }
+  
+  /* get ready to read data on images */ 
+  f = fopen (ImageCat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open image catalog %s\n", ImageCat);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+  
+  /* read in image data */
+  Nimage = 0;
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (image, Image, Nimage);
+  nimage = Fread (image, sizeof(Image), Nimage, f, "image");
+  fclose (f);
+  if (nimage != Nimage) {
+    fprintf (stderr, "error reading all data from image file (%d != %d)\n", nimage, Nimage);
+    free (image);
+    return (FALSE);
+  }
+  
+  if (First) {
+    ptr = &image[entry].coords.crpix1;
+    for (i = 0; i < 22; i++) {
+      fprintf (GetOutfile(), "%2d: %g\n", i, ptr[i]);
+    }
+    value = image[entry].coords.pc1_1*image[entry].coords.pc2_2 + image[entry].coords.pc1_2*image[entry].coords.pc2_1;
+    fprintf (GetOutfile(), " x: %g\n", value);
+    return (TRUE);
+  }
+  
+  big = nominal * 1.05;
+  small = nominal / 1.05;
+  if (big < small) {
+    double tmp;
+    tmp = big; big = small; small = tmp;
+  }
+  
+  badim_int = FALSE;
+  if (Cross) {
+    for (i = 0; (i < Nimage) && !badim_int; i++) {
+      value = image[i].coords.pc1_1*image[i].coords.pc2_2 + image[i].coords.pc1_2*image[i].coords.pc2_1;
+      if ((value > big) || (value < small)) {
+	fprintf (GetOutfile(), "%5d %s: %d %g\n", i, image[i].name, image[i].tzero, value);
+      }
+    }
+  } else {
+    for (i = 0; (i < Nimage) && !badim_int; i++) {
+      ptr = &image[i].coords.crpix1;
+      if ((ptr[entry] > big) || (ptr[entry] < small)) {
+	fprintf (GetOutfile(), "%5d %s: %d %g\n", i, image[i].name, image[i].tzero, ptr[entry]);
+      }
+    }
+  }
+  
+  return (TRUE);
+
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calextract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calextract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calextract.c	(revision 21703)
@@ -0,0 +1,149 @@
+# include "dvo1.h"
+
+enum {Nd, Nm, NC, NR, ND, Np, Nc, Nt, Nx, Nd1, Nd2, NVEC};
+
+int calextract (int argc, char **argv) {
+  
+  int i, j, m, N, Nr, Nregions, mode[2];
+  int Nsec, NSTAR;
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double M1, M2, dM2, color;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[2];
+  Vector **vec;
+
+  /* these need to be freed in the end */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  vec = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* command line arguments */
+  SetSelectionParam (0);
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 2)) goto usage;
+
+  if (argc != 4) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  /* code.type must be PHOT_REF */
+
+  /* one unique value per star */
+  N = 0;
+  NSTAR = 1;
+  ALLOCATE (vec, Vector *, NVEC);
+  if ((vec[Nd] 	= SelectVector ("cal:dmag",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm] 	= SelectVector ("cal:mag",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NC] 	= SelectVector ("cal:color",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NR] 	= SelectVector ("cal:ra",       ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[ND] 	= SelectVector ("cal:dec",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Np] 	= SelectVector ("cal:nphot",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nc] 	= SelectVector ("cal:ncode",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nt] 	= SelectVector ("cal:ncrit",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nx] 	= SelectVector ("cal:chisq",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd1] = SelectVector ("cal:dm1",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd2] = SelectVector ("cal:dm2",      ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  for (Nr = 0; Nr < Nregions; Nr++) {
+    if (Nr && !(Nr % 500)) { fprintf (stderr, "."); }
+
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[Nr].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* extract values, assign to vectors */
+    for (i = 0; i < catalog.Naverage; i++) {
+      if (i && !(i % 10000)) { fprintf (stderr, ","); }
+      m = catalog.average[i].offset;
+
+      if (code[0][0].c1 && code[0][0].c2 && !PhotColor (&catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], code[0][0].c1, code[0][0].c2, &color)) continue;
+
+      /* find data for filter 2 (PHOT_REF) */
+      M2 = NO_MAG;
+      dM2 = NO_MAG;
+      for (j = 0; j < catalog.average[i].Nm; j++) {
+	if (catalog.measure[m+j].source != code[1][0].code) continue;
+	M2 = PhotCat  (&catalog.measure[m+j]);
+	dM2 = 0.001*catalog.measure[m+j].dM;
+      }	
+      if (M2 == NO_MAG) continue;
+
+      /* find data for filter 1 */
+      M1 = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_MAG);
+      if (M1 == NO_MAG) continue;
+
+      vec[Nd ][0].elements[N] = M1 - M2;
+      vec[Nm ][0].elements[N] = M2;
+      vec[NC ][0].elements[N] = color;
+      vec[NR ][0].elements[N] = catalog.average[i].R;
+      vec[ND ][0].elements[N] = catalog.average[i].D;
+      vec[Nd1][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_dMAG);
+      vec[Nd2][0].elements[N] = dM2;
+      vec[Nx ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_Xm);
+      vec[Nc ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NCODE);
+      vec[Np ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NPHOT);
+      vec[Nt ][0].elements[N] = ExtractAverages (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], AVE_NCRIT);
+      N ++;
+      if (N == NSTAR) {
+	NSTAR += 100;
+	for (j = 0; j < NVEC; j++) {
+	  REALLOCATE (vec[j][0].elements, float, NSTAR);
+	}
+      }
+    }
+    if (catalog.average != (Average *) NULL) free (catalog.average);
+    if (catalog.measure != (Measure *) NULL) free (catalog.measure);
+    if (catalog.secfilt != (SecFilt *) NULL) free (catalog.secfilt);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    vec[i][0].Nelements = N;
+  }
+  return (TRUE);
+  
+usage:
+  fprintf (stderr, "USAGE: calextract F - F\n");
+  return (FALSE);
+
+ escape:
+  
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    DeleteVector (vec[i]);
+  }
+  free (vec);
+
+  return (FALSE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calmextract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calmextract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/calmextract.c	(revision 21703)
@@ -0,0 +1,195 @@
+# include "dvo1.h"
+
+enum {Nd, Nm1, Nm2, Nc, Ns, Nt, Nz, NR, ND, Nxc, Nyc, Nxm, Nym, NT, NP, Nd1, Nd2, NVEC};
+int ConcatMeasures (Vector *vec, PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int param, int Nin);
+
+int calmextract (int argc, char **argv) {
+  
+  int i, j, k, m, N, N1, Nr, mode[2];
+  int NSTAR, Nstar, Nsec, Nregions;
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, M2, dM2, color;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[2];
+  Vector **vec;
+
+  /* these need to be freed in the end */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  vec = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* command line arguments */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 2)) goto usage;
+
+  /* interpret required command-line arguments: calmextract F1 - F2 */
+  if (argc != 4) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if (!TestPhotSelections (&code[0], &mode[0], MEAS_ZERO)) goto escape;
+
+  /* returned vectors are dmag, mag, color, time, airmass, ra, dec, x, y, exptime */
+  N = 0;
+  Nstar = 0;
+  NSTAR = 100;
+  ALLOCATE (vec, Vector *, NVEC);
+  if ((vec[Nd ] = SelectVector ("cal:dmag",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm1] = SelectVector ("cal:mag1",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nm2] = SelectVector ("cal:mag2",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nc ] = SelectVector ("cal:color",    ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Ns ] = SelectVector ("cal:star",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nt ] = SelectVector ("cal:time",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nz ] = SelectVector ("cal:airmass",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NR ] = SelectVector ("cal:ra",       ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[ND ] = SelectVector ("cal:dec",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nxc] = SelectVector ("cal:xccd",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nyc] = SelectVector ("cal:yccd",     ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nxm] = SelectVector ("cal:xmosaic",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nym] = SelectVector ("cal:ymosaic",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NT ] = SelectVector ("cal:exptime",  ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[NP ] = SelectVector ("cal:photcode", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd1] = SelectVector ("cal:dm1",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((vec[Nd2] = SelectVector ("cal:dm2",      ANYVECTOR, TRUE)) == NULL) goto escape;
+  for (k = 0; k < NVEC; k++) {
+    REALLOCATE (vec[k][0].elements, float, NSTAR);
+    vec[k][0].Nelements = 0;
+  }
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+  if (!SetImageSelection (MEAS_XMOSAIC)) goto escape;
+
+  for (Nr = 0; Nr < Nregions; Nr++) {
+    if (Nr && !(Nr % 500)) { fprintf (stderr, "."); }
+
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[Nr].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* extract values, assign to vectors */
+    for (i = 0; i < catalog.Naverage; i++) {
+      m = catalog.average[i].offset;
+
+      /* PRI/SEC must have data for color term */
+      if (code[0][0].c1 && code[0][0].c2 && !PhotColor (&catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], code[0][0].c1, code[0][0].c2, &color)) continue;
+
+      /* find data for filter 2 (REF) */
+      M2 = NO_MAG;
+      dM2 = NO_MAG;
+      for (j = 0; j < catalog.average[i].Nm; j++) {
+	if (catalog.measure[m+j].source != code[1][0].code) continue;
+	M2 = PhotCat  (&catalog.measure[m+j]); 
+	dM2 = 0.001*catalog.measure[m+j].dM;
+      }	
+      if (M2 == NO_MAG) continue;
+      
+      /* find data for filter 1 */
+      M1 = ExtractMeasures (code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1, MEAS_MAG);
+      if (N1 == 0) goto skip;
+
+      /* extend storage vectors to take new data, if needed */
+      if (N + N1 >= NSTAR) {
+	NSTAR += N1 + 100;
+	for (k = 0; k < NVEC; k++) {
+	  REALLOCATE (vec[k][0].elements, float, NSTAR);
+	}
+      }
+
+      ConcatMeasures (vec[Nt ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_TIME); 
+      ConcatMeasures (vec[Nz ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_AIRMASS); 
+      ConcatMeasures (vec[NT ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_EXPTIME); 
+      ConcatMeasures (vec[NP ], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_PHOTCODE); 
+      ConcatMeasures (vec[Nd1], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_dMAG); 
+      ConcatMeasures (vec[Nxc], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_XCCD); 
+      ConcatMeasures (vec[Nyc], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_YCCD); 
+      ConcatMeasures (vec[Nxm], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_XMOSAIC); 
+      ConcatMeasures (vec[Nym], code[0], mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], N1, MEAS_YMOSAIC); 
+
+      for (j = 0; j < N1; j++, N++) {
+	vec[Nd ][0].elements[N] = M1[j] - M2;
+	vec[Nm1][0].elements[N] = M1[j];
+	vec[Nm2][0].elements[N] = M2;
+	vec[Nd2][0].elements[N] = dM2;
+	vec[Nc ][0].elements[N] = color;
+	vec[Ns ][0].elements[N] = Nstar;
+	vec[NR ][0].elements[N] = catalog.average[i].R;
+	vec[ND ][0].elements[N] = catalog.average[i].D;
+      }
+      Nstar ++; 
+    skip:
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != (Average *) NULL) free (catalog.average);
+    if (catalog.measure != (Measure *) NULL) free (catalog.measure);
+    if (catalog.secfilt != (SecFilt *) NULL) free (catalog.secfilt);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    vec[i][0].Nelements = N;
+  }
+  FreeImageSelection ();
+  return (TRUE);
+  
+usage:
+  fprintf (stderr, "USAGE: dmags F - F : measure.param\n");
+  return (FALSE);
+
+ escape:
+  
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);  
+  for (i = 0; i < NVEC; i++) {
+    DeleteVector (vec[i]);
+  }
+  free (vec);
+  return (FALSE);
+}
+
+int ConcatMeasures (Vector *vec, PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int Nin, int param) {
+
+  int i, Ns, N;
+  double *value;
+
+  value = ExtractMeasures (code, mode, average, secfilt, measure, &N, param); 
+  if (N != Nin) {
+    fprintf (stderr, "error!\n");
+    return (FALSE);
+  }
+
+  Ns = vec[0].Nelements;
+  for (i = 0; i < N; i++) {
+    vec[0].elements[Ns+i] = value[i];
+  }
+  vec[0].Nelements = Ns + N;
+
+  free (value);
+  return (TRUE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/catalog.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/catalog.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/catalog.c	(revision 21703)
@@ -0,0 +1,410 @@
+# include "dvo1.h"
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+# define MAGSCALE 0
+# define NUMSCALE 1
+# define MISSCALE 2
+
+int catlog (int argc, char **argv) {
+  
+  FILE *f;
+  Catalog catalog;
+  Vector Xvec, Yvec, Zvec;
+  int i, N, Nm, Nn, NN, Nbytes, nbytes, Bytes_Star;
+  int Ar, Ad, Am, InRegion, GSC, ASCII, DVO, FIXED;
+  char filename[128];
+  double Mz, Mr, Nz, Nr;
+  int clip, mode, IDclip, IDchoice, LimExclude;
+  RegionFile *regions;
+  int j, Nregions;
+  double Radius, Rmin, Rmax;
+  Graphdata graphmode;
+  double epoch, current_epoch;
+  char gscdir[256], catdir[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+
+  Mz = 17.0;
+  Mr = -5.0;
+  mode = MAGSCALE;
+  clip = FALSE;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  regions = (RegionFile *) NULL;
+  f = (FILE *) NULL;
+  Nz = Nr = Am = Ar = Ad = 0;
+  /* either MagScale or NumScale, whichever is first is scale */
+  Nm = get_argument (argc, argv, "-m");
+  Nn = get_argument (argc, argv, "+n");
+  NN = get_argument (argc, argv, "-n");
+  if (NN && Nn) {
+    fprintf (stderr, "can't mix meas and miss scaling\n");
+    return (FALSE);
+  }
+ 
+  if (Nm)
+    mode = MAGSCALE;
+  if (Nn)
+    mode = NUMSCALE;
+  if (NN)
+    mode = MISSCALE;
+    
+  if (Nm && Nn) {
+    clip = TRUE;
+    if (Nm < Nn) 
+      mode = MAGSCALE;
+    else 
+      mode = NUMSCALE;
+  }
+  if (Nm && NN) {
+    clip = TRUE;
+    if (Nm < NN) 
+      mode = MAGSCALE;
+    else 
+      mode = MISSCALE;
+  }
+   
+  current_epoch = 2000.0;
+  epoch = 2000.0;
+  if ((N = get_argument (argc, argv, "-e"))) {
+    remove_argument (N, &argc, argv);
+    epoch  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  IDchoice = 0;
+  IDclip = FALSE;
+  if ((N = get_argument (argc, argv, "-ID"))) {
+    remove_argument (N, &argc, argv);
+    IDchoice  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    IDclip = TRUE;
+  }
+
+  LimExclude = FALSE;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    LimExclude = TRUE;
+  }
+
+  if ((Nm = get_argument (argc, argv, "-m"))) {
+    remove_argument (Nm, &argc, argv);
+    Mr  = 1000*atof(argv[Nm]);
+    remove_argument (Nm, &argc, argv);
+    Mz = 1000*atof(argv[Nm]);
+    Mr = Mr - Mz;
+    remove_argument (Nm, &argc, argv);
+  }
+
+  if ((Nn = get_argument (argc, argv, "+n"))) {
+    remove_argument (Nn, &argc, argv);
+    Nz  = atof(argv[Nn]);
+    remove_argument (Nn, &argc, argv);
+    Nr = atof(argv[Nn]) - Nz;
+    remove_argument (Nn, &argc, argv);
+  }
+
+  if ((Nn = get_argument (argc, argv, "-n"))) {
+    remove_argument (Nn, &argc, argv);
+    Nz  = atof(argv[Nn]);
+    remove_argument (Nn, &argc, argv);
+    Nr = atof(argv[Nn]) - Nz;
+    remove_argument (Nn, &argc, argv);
+  }
+
+  InRegion = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    InRegion = TRUE;
+  }
+
+  Bytes_Star = 0;
+  ASCII = FALSE;
+  DVO = TRUE;
+  GSC = FALSE;
+  FIXED = FALSE;
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    GSC = TRUE;
+    ASCII = FALSE;
+    DVO = FALSE;
+  }
+
+  if ((N = get_argument (argc, argv, "-a"))) {
+    remove_argument (N, &argc, argv);
+    ASCII = TRUE;
+    GSC = FALSE;
+    DVO = FALSE;
+    Ar = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Ad = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Am = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    if ((N = get_argument (argc, argv, "-f"))) {
+      remove_argument (N, &argc, argv);
+      FIXED = TRUE;
+      ASCII = FALSE;
+      Bytes_Star = atof(argv[N]);
+      remove_argument (N, &argc, argv);
+    }
+  }
+
+  
+  if ((InRegion || (argc != 2)) && (!InRegion || (argc != 1))) {
+    fprintf (stderr, "USAGE: catalog (filename / -all) [-m M M] [-n N N] [-g] [-a RA DEC MAG] \n");
+    return (FALSE);
+  }
+  
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  for (j = 0; j < Nregions; j++) {
+    catalog.average = 0;
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (ASCII) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open catalog file: %s\n", argv[1]);
+	return (FALSE);
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, 1024);
+      ALLOCATE (catalog.average, Average, NSTARS);
+      while (scan_line (f, tbuffer) != EOF) {
+	dparse (&R, Ar, tbuffer);
+	dparse (&D, Ad, tbuffer);
+	dparse (&M, Am, tbuffer);
+	catalog.average[nstar].R = R;
+	catalog.average[nstar].D = D;
+	catalog.average[nstar].M = M * 1000.0;
+	nstar++;
+	if (nstar == NSTARS - 1) {
+	  NSTARS += DNSTARS;
+	  REALLOCATE (catalog.average, Average, NSTARS);
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+
+      if (epoch != current_epoch) {
+	cprecess (catalog.average, catalog.Naverage, epoch, current_epoch);
+      }
+
+    }
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (FIXED) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open catalog file: %s\n", argv[1]);
+	return (FALSE);
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, (BLOCK*Bytes_Star));
+      ALLOCATE (catalog.average, Average, NSTARS);
+      Nbytes = BLOCK*Bytes_Star;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / Bytes_Star; i++) {
+	  dparse (&R, Ar, &tbuffer[i*Bytes_Star]);
+	  dparse (&D, Ad, &tbuffer[i*Bytes_Star]);
+	  dparse (&M, Am, &tbuffer[i*Bytes_Star]);
+	  catalog.average[nstar].R = R;
+	  catalog.average[nstar].D = D;
+	  catalog.average[nstar].M = M * 1000.0;
+	  nstar++;
+	  if (nstar == NSTARS - 1) {
+	    NSTARS += DNSTARS;
+	    REALLOCATE (catalog.average, Average, NSTARS);
+	  }
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+
+      if (epoch != current_epoch) {
+	cprecess (catalog.average, catalog.Naverage, epoch, current_epoch);
+      }
+
+    }
+    
+    /* load data from the GSC files */
+    if (GSC) {
+      char *tbuffer;
+      int nstar, NSTARS;
+      double R, D, M;
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s", gscdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s", gscdir, argv[1]);
+      }
+      
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "no stars in %s, skipping\n", filename);
+	continue;
+	/* return (FALSE); */
+      }
+      
+      nstar = 0;
+      NSTARS = DNSTARS;
+      ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+      ALLOCATE (catalog.average, Average, NSTARS);
+      Nbytes = BLOCK*BYTES_STAR;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	  dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+	  dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+	  dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+	  catalog.average[nstar].R = R;
+	  catalog.average[nstar].D = D;
+	  catalog.average[nstar].M = M * 1000.0;
+	  nstar++;
+	  if (nstar == NSTARS - 1) {
+	    NSTARS += DNSTARS;
+	    REALLOCATE (catalog.average, Average, NSTARS);
+	  }
+	}
+      }
+      fclose (f);
+      free (tbuffer);
+      REALLOCATE (catalog.average, Average, nstar);
+      catalog.Naverage = nstar;
+    }
+  
+    /* load data from the photometry database files */
+    if (DVO) {
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s", catdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s", catdir, argv[1]);
+      }
+      
+      /* lock, load, unlock catalog */
+      catalog.filename = filename;
+      switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+      }
+      if (!load_catalog (&catalog, LOAD_AVES, TRUE)) {
+	unlock_catalog (&catalog);
+	continue;
+      }
+      unlock_catalog (&catalog);
+    }
+    
+    /* data has been loaded, get ready to plot it */
+    Xvec.Nelements = catalog.Naverage;
+    Yvec.Nelements = catalog.Naverage;
+    Zvec.Nelements = catalog.Naverage;
+    ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+    ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+    ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+    /* project stars to screen display coords */
+    Xvec.Nelements = 0;
+    switch (mode) {
+    case (MAGSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].Nm < Nz) || (catalog.average[i].Nm > Nr+Nz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].M - Mz) / Mr));
+	if (LimExclude && (Zvec.elements[N] > 0.99)) continue;
+	if (Zvec.elements[N] < 0.011) continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N ++;
+      }
+      break;
+    case (NUMSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].M > Mz) || (catalog.average[i].M < Mr+Mz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].Nm - Nz) / Nr));
+	if (LimExclude && (Zvec.elements[N] == 1.0)) continue;
+	if (Zvec.elements[N] == 0.01) 
+	  continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N++;
+      }
+      break;
+    case (MISSCALE):
+      for (N = i = 0; i < catalog.Naverage; i++) {
+	if (clip && ((catalog.average[i].M > Mz) || (catalog.average[i].M < Mr+Mz))) 
+	  continue;
+	if (IDclip && (catalog.average[i].code != IDchoice))
+	  continue;
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (catalog.average[i].Nn - Nz) / Nr));
+	if (LimExclude && (Zvec.elements[N] == 1.0)) continue;
+	if (Zvec.elements[N] == 0.01) 
+	  continue;
+	while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+	while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+	if (fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R, catalog.average[i].D, &graphmode.coords)) N++;
+      }
+      break;
+    }
+
+    Zvec.Nelements = Yvec.Nelements = Xvec.Nelements = N;
+    REALLOCATE (Xvec.elements, float, MAX (Xvec.Nelements, 1));
+    REALLOCATE (Yvec.elements, float, MAX (Yvec.Nelements, 1));
+    REALLOCATE (Zvec.elements, float, MAX (Zvec.Nelements, 1));
+    
+    graphmode.style = 2; /* set style to points */
+    graphmode.size = -1; /* point size determined by Zvec */
+    graphmode.etype = 0; /* no errorbars */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+    PlotVector (N, Zvec.elements);
+    
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+
+    if (catalog.average != 0) free (catalog.average);
+
+  }
+  return (TRUE);
+
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ccd.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ccd.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ccd.c	(revision 21703)
@@ -0,0 +1,139 @@
+# include "dvo1.h"
+
+int ccd (int argc, char **argv) {
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, *M2;
+  int i, m, k, Npts, NPTS, N;
+  int N1, N2, i1, i2, mode[4];
+  int Nsec, Nregions, KeepNulls;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[4];
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 4)) goto usage;
+
+  KeepNulls = FALSE;
+  if ((N = get_argument (argc, argv, "-nulls"))) {
+    KeepNulls = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret command-line options */
+  if (argc != 8) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (strcmp (argv[6], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[7], &code[3], &mode[3])) return (FALSE);
+  if (!TestPhotSelections (&code[0], &mode[0], MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (k = 0; k < Nregions; k++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M2 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (&code[0], &mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M2 = ExtractDMag (&code[2], &mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N2);
+      if (N2 == 0) {
+	if (KeepNulls) {
+	  ALLOCATE (M2, double, 1);
+	  N2 = 1;
+	  M2[0] = NO_MAG;
+	} else {
+	  goto skip;
+	}
+      }
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i2 = 0; i2 < N2; i2++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M2[i2];
+	  Npts++;
+	  if (Npts >= NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M2 != NULL) free (M2);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: ccd F - F : F - F\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmatch.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmatch.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmatch.c	(revision 21703)
@@ -0,0 +1,115 @@
+# include "dvo1.h"
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+int cmatch (int argc, char **argv) {
+  
+  FILE *f;
+  Catalog catalog1, catalog2;
+  int i, Nbytes, nbytes, Nitems, nitems;
+  char *tbuffer, filename[128];
+  int nstar, NSTARS;
+  double R, D, M, radius;
+  char catdir[256], gscdir[256];
+  Vector *rvec, *dvec, *mvec, *drvec, *ddvec, *dmvec;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+      
+  if (argc != 9) {
+    fprintf (stderr, "USAGE: cmatch file radius (RA) (DEC) (Mag) (dRA) (dDEC) (dMag)\n");
+    return (FALSE);
+  }
+
+  radius = atof (argv[2]);
+
+  if ((rvec  = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((dvec  = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((mvec  = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((drvec = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((ddvec = SelectVector (argv[7], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((dmvec = SelectVector (argv[8], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* load data from the photometry database file */
+  sprintf (filename, "%s/%s", catdir, argv[1]);
+  if (!fits_read_header (filename, &catalog1.header)) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    return (FALSE);
+  }
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    return (FALSE);
+  }
+  fseek (f, catalog1.header.size, SEEK_SET); 
+  
+  /** find number of stars, measurements **/
+  catalog1.Naverage = 0;
+  fits_scan (&catalog1.header, "NSTARS", "%d", 1, &catalog1.Naverage);
+  if (catalog1.Naverage == 0) {
+    fprintf (stderr, "no stars in catalog %s\n", filename);
+    fclose (f);
+    return (TRUE);
+  }
+  ALLOCATE (catalog1.average, Average, catalog1.Naverage);
+  Nitems = catalog1.Naverage;
+  nitems = Fread (catalog1.average, sizeof(Average), Nitems, f, "average");
+  if (nitems != Nitems) {
+    fprintf (stderr, "ERROR: failed to read data from catalog file %s (1)\n", filename);
+    fclose (f);
+    free (catalog1.average);
+    return (FALSE);
+  }
+  fclose (f);
+  fprintf (stderr, "read %d stars from phot catalog file %s\n", catalog1.Naverage, filename);
+
+  /* load data from the GSC file */
+  sprintf (filename, "%s/%s", gscdir, argv[1]);
+  f = fopen (filename, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "no stars in %s\n", filename);
+    free (catalog1.average);
+    return (FALSE);
+    /* return (FALSE); */
+  }
+  
+  nstar = 0;
+  NSTARS = DNSTARS;
+  ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+  ALLOCATE (catalog2.average, Average, NSTARS);
+  Nbytes = BLOCK*BYTES_STAR;
+  while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+    for (i = 0; i < nbytes / BYTES_STAR; i++) {
+      dparse (&R, 1, &tbuffer[i*BYTES_STAR]);
+      dparse (&D, 2, &tbuffer[i*BYTES_STAR]);
+      dparse (&M, 3, &tbuffer[i*BYTES_STAR]);
+      catalog2.average[nstar].R = R;
+      catalog2.average[nstar].D = D;
+      catalog2.average[nstar].M = M * 1000.0;
+      nstar++;
+      if (nstar == NSTARS - 1) {
+	NSTARS += DNSTARS;
+	REALLOCATE (catalog2.average, Average, NSTARS);
+      }
+    }
+  }
+  free (tbuffer);
+  REALLOCATE (catalog2.average, Average, MAX (nstar, 1));
+  catalog2.Naverage = nstar;
+  fclose (f);
+
+  /* sort data in order of RA */
+  sortave (catalog1.average, catalog1.Naverage);
+  sortave (catalog2.average, catalog2.Naverage);
+
+  /* data has been loaded, use gcompare algorithm to match */
+  compare (&catalog1, &catalog2, rvec, dvec, mvec, drvec, ddvec, dmvec, radius);
+
+  free (catalog1.average);
+  free (catalog2.average);
+
+  return (TRUE);
+
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmd.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmd.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmd.c	(revision 21703)
@@ -0,0 +1,137 @@
+# include "dvo1.h"
+
+int cmd (int argc, char **argv) { /* really need to think about upper limits & how to represent them */
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, *M3;
+  int i, j, m, i1, i3, N1, N3, N;
+  int Npts, NPTS, mode[3];
+  int Nsec, Nregions, KeepNulls;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 3)) goto usage;
+
+  KeepNulls = FALSE;
+  if ((N = get_argument (argc, argv, "-nulls"))) {
+    KeepNulls = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret command-line options */
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+  if (!TestPhotSelections (&code[0], &mode[0], MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+    
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M3 = ExtractMagnitudes (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3);
+      if (N3 == 0) {
+	if (KeepNulls) {
+	  ALLOCATE (M3, double, 1);
+	  N3 = 1;
+	  M3[0] = NO_MAG;
+	} else {
+	  goto skip;
+	}
+      }
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i3 = 0; i3 < N3; i3++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M3[i3];
+	  Npts++;
+	  if (Npts >= NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: cmd F - F : F\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
+    
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpload.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpload.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpload.c	(revision 21703)
@@ -0,0 +1,154 @@
+# include "dvo1.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+
+int cmpload (int argc, char **argv) {
+  
+  int i, nstar, N, Nin, Nout, Nextra, n, Type, type;
+  int doneread, done, Nskip, Nbytes, nbytes, Ninstar;
+  char *c, *c2;
+  double *X, *Y, *M;
+  double dtmp;
+  FILE *f;
+  char *buffer, *buffer2;
+  int Ximage, Nimage;
+  Header header;
+  
+  Nimage = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Nimage = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (&Ximage, &Nimage)) return (FALSE);
+
+  Type = 0;
+  if ((N = get_argument (argc, argv, "-t"))) {
+    remove_argument (N, &argc, argv);
+    Type = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: load (overlay) <filename>\n");
+    return (FALSE);
+  }
+
+  if (!SelectOverlay (argv[1], &n)) 
+    return (FALSE);
+
+  if (!fits_read_header (argv[2], &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", argv[2]);
+    return (FALSE);
+  }
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &nstar);
+  if (nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    fits_free_header (&header);
+    return (FALSE);
+  }
+
+  f = fopen (argv[2], "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", argv[2]);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  ALLOCATE (X, double, nstar);
+  ALLOCATE (Y, double, nstar);
+  ALLOCATE (M, double, nstar);
+
+  /* load in stars by blocks of 1000 */
+  Nin = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR) + 1);
+  buffer[BLOCK*BYTES_STAR] = 0;
+  Nextra = 0;
+  doneread = FALSE;
+  while (!doneread) {
+    Nbytes = BYTES_STAR * BLOCK - Nextra;
+    nbytes = fread (&buffer[Nextra], 1, Nbytes, f);
+    if (nbytes == 0) {
+      doneread = TRUE;
+      continue;
+    }
+    nbytes += Nextra;
+    /* check line-by-line integrity */
+    c = buffer;
+    done = FALSE;
+    while ((c < buffer + nbytes) && (!done)) { 
+      for (c2 = c; *c2 == '\n'; c2++);
+      if (c2 > c) { /* extra return chars */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+      }
+      c2 = strchr (c, '\n');
+      if (c2 == (char *) NULL) {
+	done = TRUE;	
+	continue;
+      }
+      c2++;
+      if ((c2 - c) != BYTES_STAR) { /* bad line, delete it */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (i = 0; i < Ninstar; i++, Nin++) {
+      dparse (&X[Nin],  1, &buffer[i*BYTES_STAR]);
+      dparse (&Y[Nin],  2, &buffer[i*BYTES_STAR]);
+      dparse (&M[Nin],  3, &buffer[i*BYTES_STAR]);
+      if (Type) {
+	dparse (&dtmp, 5, &buffer[i*BYTES_STAR]);
+	type = dtmp;
+	if (type != Type) {
+	  Nin --;
+	}
+      }
+    }
+  }
+  fclose (f);
+
+  SendGraphCommand (Ximage, 4, "LOAD");
+  SendGraphCommand (Ximage, 16, "OVER %9d ", n);
+  ALLOCATE (buffer2, char, 66000);
+  bzero (buffer2, 65536);
+
+  for (Nout = i = 0; i < Nin; i++, Nout++) {
+    sprintf (&buffer2[Nout*128], "%15s %20.10f %20.10f %20.10f %20.10f ", "BOX", X[i], Y[i], 5.0, 5.0);
+    if (Nout == 512) {
+      SendGraphCommand (Ximage, 16, "NLINES  %7d ", Nout);
+      write (Ximage, buffer2, Nout*128);
+      bzero (buffer2, 65536);
+      Nout = -1;
+    }
+  }
+
+  if (Nout) {
+    SendGraphCommand (Ximage, 16, "NLINES  %7d ", Nout);
+    write (Ximage, buffer2, Nout*128);
+  }
+  SendGraphCommand (Ximage, 16, "DONE");
+
+  fits_free_header (&header);
+  free (X);
+  free (Y);
+  free (M);
+  free (buffer);
+  free (buffer2);
+
+  fprintf (stderr, "loaded %d objects\n", Nin);
+  return (TRUE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpread.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpread.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/cmpread.c	(revision 21703)
@@ -0,0 +1,154 @@
+# include "dvo1.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 66
+# define BLOCK 1000
+
+int cmpread (int argc, char **argv) {
+  
+  int i, nstar, Nin, Nextra;
+  int doneread, done, Nskip, Nbytes, nbytes, Ninstar, RAnDEC;
+  char *c, *c2, *name, *file;
+  float *R, *D, *V;
+  double tR, tD, tmp, X, Y;
+  FILE *f;
+  char *buffer;
+  int Nfield, Nra, Ndec;
+  Vector *rvec, *dvec, *vec;
+  Header header;
+  Coords coords;
+
+  if ((argc != 4) && (argc != 6)) {
+    fprintf (stderr, "USAGE: cmpread name Nfield <filename>\n");
+    fprintf (stderr, "USAGE: cmpread ra N dec N <filename>\n");
+    return (FALSE);
+  }
+
+  R = D = V = NULL;
+  file = NULL;
+  name = NULL;
+  Nfield = Nra = Ndec = 0;
+  RAnDEC = FALSE;
+
+  if (argc == 4) {
+    name = strcreate (argv[1]);
+    Nfield = atof (argv[2]);
+    file = strcreate (argv[3]);
+    RAnDEC = FALSE;
+  } else {
+    Nra  = atof (argv[2]);
+    Ndec = atof (argv[4]);
+    file = strcreate (argv[5]);
+    RAnDEC = TRUE;
+  }    
+
+  if (!fits_read_header (file, &header)) {
+    fprintf (stderr, "ERROR: can't read header for %s\n", file);
+    free (file);
+    if (!RAnDEC) free (name);
+    return (FALSE);
+  }
+
+  /* find expected number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &nstar);
+  if (nstar == 0) {
+    fprintf (stderr, "ERROR: can't get NSTARS from header\n");
+    free (file);
+    if (!RAnDEC) free (name);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+
+  f = fopen (file, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't read data from %s\n", file);
+    free (file);
+    if (!RAnDEC) free (name);
+    fits_free_header (&header);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  if (RAnDEC) {
+    if ((rvec = SelectVector ("ra",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((dvec = SelectVector ("dec",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    REALLOCATE (rvec[0].elements, float, nstar);
+    REALLOCATE (dvec[0].elements, float, nstar);
+    R = rvec[0].elements;
+    D = dvec[0].elements;
+    rvec[0].Nelements = dvec[0].Nelements = nstar;
+    if (!GetCoords (&coords, &header)) {
+      fprintf (stderr, "can't get WCS info from header\n");
+      return (FALSE);
+    }
+  } else {
+    if ((vec = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    REALLOCATE (vec[0].elements, float, nstar);
+    V = vec[0].elements;
+    vec[0].Nelements = nstar;
+  }
+
+  /* load in stars by blocks of 1000 */
+  Nin = 0;
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR) + 1);
+  buffer[BLOCK*BYTES_STAR] = 0;
+  Nextra = 0;
+  doneread = FALSE;
+  while (!doneread) {
+    Nbytes = BYTES_STAR * BLOCK - Nextra;
+    nbytes = fread (&buffer[Nextra], 1, Nbytes, f);
+    if (nbytes == 0) {
+      doneread = TRUE;
+      continue;
+    }
+    nbytes += Nextra;
+    /* check line-by-line integrity */
+    c = buffer;
+    done = FALSE;
+    while ((c < buffer + nbytes) && (!done)) { 
+      for (c2 = c; *c2 == '\n'; c2++);
+      if (c2 > c) { /* extra return chars */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+      }
+      c2 = strchr (c, '\n');
+      if (c2 == (char *) NULL) {
+	done = TRUE;	
+	continue;
+      }
+      c2++;
+      if ((c2 - c) != BYTES_STAR) { /* bad line, delete it */
+	memmove (c, c2, (int)(buffer + nbytes - c2));
+	Nskip = c2 - c;
+	nbytes -= Nskip;
+	bzero (buffer + nbytes, Nskip);
+      } else {
+	c = c2;
+      }
+    }
+    Ninstar = nbytes / BYTES_STAR;
+    Nextra = nbytes % BYTES_STAR;
+    for (i = 0; i < Ninstar; i++, Nin++) {
+      if (RAnDEC) {
+	dparse (&X, Nra,  &buffer[i*BYTES_STAR]);
+	dparse (&Y, Ndec, &buffer[i*BYTES_STAR]);
+	XY_to_RD (&tR, &tD, X, Y, &coords);
+	R[Nin] = tR; D[Nin] = tD;
+      } else {
+	dparse (&tmp, Nfield, &buffer[i*BYTES_STAR]);
+	V[Nin] = tmp;
+      }
+    }
+  }
+  fclose (f);
+
+  fits_free_header (&header);
+  free (buffer);
+  free (file);
+  if (!RAnDEC) free (name);
+
+  fprintf (stderr, "loaded %d objects\n", Nin);
+  return (TRUE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/compare.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/compare.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/compare.c	(revision 21703)
@@ -0,0 +1,76 @@
+# include "dvo1.h"
+# define D_NMATCH 500;
+
+void compare (Catalog *catlog1, Catalog *catlog2, 
+	 Vector *rvec,  Vector *dvec,  Vector *mvec, Vector *drvec, Vector *ddvec, Vector *dmvec, double radius) {
+
+  int i, j, first_j, Nmatch, NMATCH;
+  double dX, dY, dR;
+
+  Nmatch = 0;
+  NMATCH = D_NMATCH;
+  REALLOCATE (rvec[0].elements, float, NMATCH);
+  REALLOCATE (dvec[0].elements, float, NMATCH);
+  REALLOCATE (mvec[0].elements, float, NMATCH);
+  REALLOCATE (drvec[0].elements, float, NMATCH);
+  REALLOCATE (ddvec[0].elements, float, NMATCH);
+  REALLOCATE (dmvec[0].elements, float, NMATCH);
+
+  for (i = j = 0; (i < catlog1[0].Naverage) && (j < catlog2[0].Naverage);) {
+    
+    dX = catlog1[0].average[i].R - catlog2[0].average[j].R;
+
+    if (!(i % 100))
+      fprintf (stderr, ".");
+    
+    if (dX <= -radius)
+      i++;
+    if (dX >= radius)
+      j++;
+
+    if (fabs (dX) < radius) {
+      first_j = j;
+      for (j = first_j; (fabs (dX) < radius) && (j < catlog2[0].Naverage); j++) {
+	dX = catlog1[0].average[i].R - catlog2[0].average[j].R;
+	dY = catlog1[0].average[i].D - catlog2[0].average[j].D;
+	dR = hypot (dX, dY);
+	if (dR < radius) {
+	   rvec[0].elements[Nmatch] = catlog1[0].average[i].R;
+	   dvec[0].elements[Nmatch] = catlog1[0].average[i].D;
+	   mvec[0].elements[Nmatch] = catlog1[0].average[i].M;
+	  drvec[0].elements[Nmatch] = dX;
+	  ddvec[0].elements[Nmatch] = dY;
+	  dmvec[0].elements[Nmatch] = catlog1[0].average[i].M - catlog2[0].average[j].M;
+	  Nmatch ++;
+	  if (Nmatch == NMATCH - 1) {
+	    NMATCH += D_NMATCH;
+	    REALLOCATE ( rvec[0].elements, float, NMATCH);
+	    REALLOCATE ( dvec[0].elements, float, NMATCH);
+	    REALLOCATE ( mvec[0].elements, float, NMATCH);
+	    REALLOCATE (drvec[0].elements, float, NMATCH);
+	    REALLOCATE (ddvec[0].elements, float, NMATCH);
+	    REALLOCATE (dmvec[0].elements, float, NMATCH);
+	  }
+	}
+      }
+      j = first_j;
+      i++;
+    }
+  }
+
+  REALLOCATE ( rvec[0].elements, float, Nmatch);
+  REALLOCATE ( dvec[0].elements, float, Nmatch);
+  REALLOCATE ( mvec[0].elements, float, Nmatch);
+  REALLOCATE (drvec[0].elements, float, Nmatch);
+  REALLOCATE (ddvec[0].elements, float, Nmatch);
+  REALLOCATE (dmvec[0].elements, float, Nmatch);
+  
+   rvec[0].Nelements = Nmatch;
+   dvec[0].Nelements = Nmatch;
+   mvec[0].Nelements = Nmatch;
+  drvec[0].Nelements = Nmatch;
+  ddvec[0].Nelements = Nmatch;
+  dmvec[0].Nelements = Nmatch;
+
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ddmags.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ddmags.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/ddmags.c	(revision 21703)
@@ -0,0 +1,138 @@
+# include "dvo1.h"
+
+int ddmags (int argc, char **argv) {
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, *M2;
+  int i, m, k, N, Npts, NPTS;
+  int N1, N2, i1, i2, mode[4];
+  int Nsec, Nregions, KeepNulls;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[4];
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 4)) goto usage;
+
+  KeepNulls = FALSE;
+  if ((N = get_argument (argc, argv, "-nulls"))) {
+    KeepNulls = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret command-line options */
+  if (argc != 8) goto usage;
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (strcmp (argv[6], "-")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) return (FALSE);
+  if (!GetPhotcodeInfo (argv[7], &code[3], &mode[3])) return (FALSE);
+  if (!TestPhotSelections (&code[0], &mode[0], MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (k = 0; k < Nregions; k++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M2 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (&code[0], &mode[0], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M2 = ExtractDMag (&code[2], &mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N2);
+      if (N2 == 0) {
+	if (KeepNulls) {
+	  ALLOCATE (M2, double, 1);
+	  N2 = 1;
+	  M2[0] = NO_MAG;
+	} else {
+	  goto skip;
+	}
+      }
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i2 = 0; i2 < N2; i2++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M2[i2];
+	  Npts++;
+	  if (Npts >= NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M2 != NULL) free (M2);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: ddmags F - F : measure.param\n");
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/detrend.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/detrend.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/detrend.c	(revision 21703)
@@ -0,0 +1,204 @@
+# include "dvo1.h"
+
+/* qualities to be extracted */
+enum {ZERO, DTIME, SKY, BIAS, FWHM, AIRM, TIME, TEMP};
+
+int detrend (int argc, char **argv) {
+ 
+  FILE *f;
+  int i, Nimage, status, N, TimeSelect;
+  char DataBase[256];
+  unsigned long int tzero, tend;
+  double trange;
+  int TypeSelect, CCDSelect, FilterSelect;
+  char *Filter;
+  int Type, mode, CCD;
+  int NVALUE;
+  float *value;
+  time_t TimeReference;
+  int TimeFormat;
+  Header header;
+  RegImage *pimage;
+  Vector *vec;
+
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-trange"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  Type = 0;
+  TypeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-type"))) {
+    remove_argument (N, &argc, argv);
+    Type = get_image_type (argv[N]);
+    if (Type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TypeSelect = TRUE;
+  }
+
+  CCD = 0;
+  CCDSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-ccd"))) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  Filter = NULL;
+  FilterSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-filter"))) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imrough (value)\n");
+    return (FALSE);
+  }
+  
+  /* identify selection */
+  mode = ZERO;
+  if (!strcasecmp (argv[1], "exptime")) mode = DTIME;
+  if (!strcasecmp (argv[1], "sky")) mode = SKY;
+  if (!strcasecmp (argv[1], "bias")) mode = BIAS;
+  if (!strcasecmp (argv[1], "fwhm")) mode = FWHM;
+  if (!strcasecmp (argv[1], "airmass")) mode = AIRM;
+  if (!strcasecmp (argv[1], "time")) mode = TIME;
+  if (!strcasecmp (argv[1], "temp")) mode = TEMP;
+  if (mode == ZERO) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " exptime, sky, bias, fwhm, airmass, time\n");
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  /* load in database header */
+  if (!fits_read_header (DataBase, &header)) {
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return (FALSE);
+  }
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET);
+
+  /* load existing data from database */
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (pimage, RegImage, Nimage);
+  status = Fread (pimage, sizeof(RegImage), Nimage, f, "regimage");
+  fclose (f);
+
+  if (status != Nimage) {
+    fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+    fits_free_header (&header);
+    free (pimage);
+    return (FALSE);
+  }
+
+  N = 0;
+  NVALUE = 1000;
+  REALLOCATE (vec[0].elements, float, NVALUE);
+  value = vec[0].elements;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  fprintf (stderr, "%ld %d\n", TimeReference, TimeFormat);
+
+  /* get data */
+  for (i = 0; i < Nimage; i++) {
+    /* skip unmatched selections */
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (pimage[i].filter, Filter))) continue;
+    if (CCDSelect && (pimage[i].ccd != CCD)) continue;
+    if (TypeSelect && (pimage[i].type != Type)) continue;
+
+    /* assign correct value */
+    switch (mode) {
+    case (DTIME):
+      value[N] = pimage[i].exptime;
+      break;
+    case (TIME):
+      value[N] = TimeValue (pimage[i].obstime, TimeReference, TimeFormat);
+      break;
+    case (SKY):
+      value[N] = pimage[i].sky;
+      break;
+    case (BIAS):
+      value[N] = pimage[i].bias;
+      break;
+    case (FWHM):
+      value[N] = pimage[i].fwhm;
+      break;
+    case (AIRM):
+      value[N] = pimage[i].airmass;
+      break;
+    case (TEMP):
+      value[N] = pimage[i].teltemp_0;
+      break;
+    }
+    N++;
+    if (N >= NVALUE - 1) {
+      NVALUE += 1000;
+      REALLOCATE (vec[0].elements, float, NVALUE);
+      value = vec[0].elements;
+    }
+  }
+
+  REALLOCATE (vec[0].elements, float, MAX (1,N));
+  vec[0].Nelements = N;
+
+  free (pimage);
+  fits_free_header (&header);
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagaves.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagaves.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagaves.c	(revision 21703)
@@ -0,0 +1,118 @@
+# include "dvo1.h"
+
+int dmagaves (int argc, char **argv) {
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, M2;
+  int i, j, k, m, N1;
+  int Npts, NPTS, param, mode[3];
+  int Nsec, Nregions;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  code[2] = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 3)) goto usage;
+
+  /* interpret command-line options: dmagaves F1 - F2 : (value) */
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if ((param = GetAverageParam (argv[5])) == AVE_ZERO) goto usage;
+  if (!TestPhotSelections (&code[2], &mode[2], param)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M2 = ExtractAverages (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], param);
+
+      for (k = 0; k < N1; k++) {
+	xvec[0].elements[Npts] = M1[k];
+	yvec[0].elements[Npts] = M2;
+	Npts++;
+	if (Npts >= NPTS) {
+	  NPTS += 2000;
+	  REALLOCATE (xvec[0].elements, float, NPTS);
+	  REALLOCATE (yvec[0].elements, float, NPTS);
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmagaves F - F : average.param\n");
+  return (FALSE);
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagmeas.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagmeas.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmagmeas.c	(revision 21703)
@@ -0,0 +1,141 @@
+# include "dvo1.h"
+
+int dmagmeas (int argc, char **argv) {
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, *M3;
+  int i, j, m, i1, i3, N1, N3, N;
+  int Npts, NPTS, param, mode[3];
+  int Nsec, Nregions, KeepNulls;
+
+  Catalog catalog;
+  RegionFile *regions;
+  PhotCode *code[3];
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  code[2] = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 3)) goto usage;
+
+  KeepNulls = FALSE;
+  if ((N = get_argument (argc, argv, "-nulls"))) {
+    KeepNulls = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret command-line arguments: dmagmeas F1 - F2 : (value) */
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if ((param = GetMeasureParam (argv[5])) == MEAS_ZERO) goto usage;
+  if (!TestPhotSelections (&code[2], &mode[2], MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+  if (!SetImageSelection (param)) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M3 = ExtractMeasures (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3, param);
+      if (N3 == 0) {
+	if (KeepNulls) {
+	  ALLOCATE (M3, double, 1);
+	  N3 = 1;
+	  M3[0] = NO_MAG;
+	} else {
+	  goto skip;
+	}
+      }
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i3 = 0; i3 < N3; i3++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M3[i3];
+	  Npts++;
+	  if (Npts >= NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmagmeas F - F : measure.param\n");
+  return (FALSE);
+
+escape:
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmags.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmags.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmags.c	(revision 21703)
@@ -0,0 +1,140 @@
+# include "dvo1.h"
+
+int dmags (int argc, char **argv) {
+  
+  char filename[256], catdir[256], *RegionName, *RegionList;
+  double *M1, *M3;
+  int i, j, m, i1, i3, N1, N3, N;
+  int Npts, NPTS, mode[3];
+  int Nsec, Nregions, KeepNulls;
+
+  PhotCode *code[3];
+  Catalog catalog;
+  RegionFile *regions;
+  Vector *xvec, *yvec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = NULL; 
+  catalog.secfilt = NULL;
+  catalog.measure = NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 3)) goto usage;
+
+  KeepNulls = FALSE;
+  if ((N = get_argument (argc, argv, "-nulls"))) {
+    KeepNulls = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* interpret required command-line arguments: dmags F1 - F2 : F3 */
+  if (argc != 6) { goto usage; }
+  if (strcmp (argv[2], "-")) goto usage;
+  if (strcmp (argv[4], ":")) goto usage;
+  if (!GetPhotcodeInfo (argv[1], &code[0], &mode[0])) goto usage;
+  if (!GetPhotcodeInfo (argv[3], &code[1], &mode[1])) goto usage;
+  if (!GetPhotcodeInfo (argv[5], &code[2], &mode[2])) goto usage;
+  if (!TestPhotSelections (&code[0], &mode[0], MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* init vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("xv", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("yv", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  for (j = 0; j < Nregions; j++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[j].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* get correct mags, convert to X,Y */
+    for (i = 0; i < catalog.Naverage; i++) {
+      M1 = M3 = NULL;
+      m = catalog.average[i].offset;
+
+      SetSelectionParam (0);
+      M1 = ExtractDMag (code, mode, &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N1);
+      if (N1 == 0) goto skip;
+
+      SetSelectionParam (2);
+      M3 = ExtractMagnitudes (code[2], mode[2], &catalog.average[i], &catalog.secfilt[i*Nsec], &catalog.measure[m], &N3);
+      if (N3 == 0) {
+	if (KeepNulls) {
+	  ALLOCATE (M3, double, 1);
+	  N3 = 1;
+	  M3[0] = NO_MAG;
+	} else {
+	  goto skip;
+	}
+      }
+
+      for (i1 = 0; i1 < N1; i1++) {
+	for (i3 = 0; i3 < N3; i3++) {
+	  xvec[0].elements[Npts] = M1[i1];
+	  yvec[0].elements[Npts] = M3[i3];
+	  Npts++;
+	  if (Npts >= NPTS) {
+	    NPTS += 2000;
+	    REALLOCATE (xvec[0].elements, float, NPTS);
+	    REALLOCATE (yvec[0].elements, float, NPTS);
+	  }
+	}
+      }
+    skip:
+      if (M1 != NULL) free (M1);
+      if (M3 != NULL) free (M3);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  if (regions != NULL) free (regions);
+  xvec[0].Nelements = yvec[0].Nelements = Npts;
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: dmags F - F : F\n");
+  fprintf (stderr, "    F : any photcodes with matched qualifiers:\n");
+  fprintf (stderr, "    pri: F:inst, F:cat, F:sys, F:rel, F:cal, F:ave, F:ref\n");
+  fprintf (stderr, "    sec: F:inst, F:cat, F:sys, F:rel, F:cal, F:ave, F:ref\n");
+  fprintf (stderr, "    dep: F:inst, F:cat, F:sys, F:rel, F:cal\n");
+  fprintf (stderr, "    ref: F:cat\n");
+
+escape:
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmt.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmt.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dmt.c	(revision 21703)
@@ -0,0 +1,155 @@
+# include "dvo1.h"
+
+/* extract vectors giving delta mags for multiple measurements */ 
+int dmt (int argc, char **argv) {
+  
+  int i, m, k, N, Nregions, Ngraph, SaveVectors;
+  int Ns, Nsec, NPTS;
+  char catdir[256], filename[256];
+  double Radius;
+  float dt1, dt2, dmt1, dmt2;
+  float M0, M1, M2, M3;
+  PhotCode *code;
+  Catalog catalog;
+  Graphdata graphmode, graphsky;
+  RegionFile *regions;
+  Vector Xvec, Yvec, Zvec, Rvec, Dvec;
+  Vector *vec1, *vec2, *vec3, *vec4, *vec5;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  vec1 = vec2 = vec3 = vec4 = vec5 = NULL;
+  SaveVectors = FALSE;
+  if ((N = get_argument (argc, argv, "-vect"))) {
+    remove_argument (N, &argc, argv);
+    if ((vec1 = SelectVector ("dmtdmt", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec2 = SelectVector ("dmtvar", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec3 = SelectVector ("dmtmag", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec4 = SelectVector ("dmtra",  ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec5 = SelectVector ("dmtdec", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    SaveVectors = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dmags filter\n");
+    return (FALSE);
+  }
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+  if (!GetGraph (&graphmode, NULL, NULL)) return (FALSE);
+
+  if ((code = GetPhotcodebyName (argv[1])) == NULL) {
+    fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+    return (FALSE);
+  }
+  if ((code[0].type != PHOT_SEC) && (code[0].type != PHOT_PRI)) {
+    fprintf (stderr, "first filter must be a PRIMARY or SECONDARY photometry type\n");
+    return (FALSE);
+  }
+  Nsec = GetPhotcodeNsecfilt();
+  Ns = GetPhotcodeNsec (code[0].code);
+
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, &Nregions);
+  
+  N = 0;
+  NPTS = catalog.Nmeasure;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  if (SaveVectors) {
+    ALLOCATE (Zvec.elements, float, NPTS);
+    ALLOCATE (Rvec.elements, float, NPTS);
+    ALLOCATE (Dvec.elements, float, NPTS);
+  }
+
+  for (k = 0; k < Nregions; k++) {
+
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    /* lock, load, unlock catalog */
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (i = 0; i < catalog.Naverage; i++) {
+      if (catalog.average[i].Nm != 3) continue;
+      m = catalog.average[i].offset;
+      M0 = (Ns == -1) ? 0.001*catalog.average[i].M : 0.001*catalog.secfilt[i*Nsec+Ns].M;
+      M1 = PhotCat (&catalog.measure[m+0]);
+      M2 = PhotCat (&catalog.measure[m+1]);
+      M3 = PhotCat (&catalog.measure[m+2]);
+
+      dt1 = (catalog.measure[m+0].t < catalog.measure[m+1].t) ? catalog.measure[m+1].t - catalog.measure[m+0].t : -1 * ((float)(catalog.measure[m+1].t - catalog.measure[m+0].t));
+      dt2 = (catalog.measure[m+1].t < catalog.measure[m+2].t) ? catalog.measure[m+2].t - catalog.measure[m+1].t : -1 * ((float)(catalog.measure[m+2].t - catalog.measure[m+1].t));
+      dmt1 = (M2 - M1) / dt1;
+      dmt2 = (M3 - M2) / dt2;
+      Xvec.elements[N] = (dmt1 - dmt2) / (dmt1 + dmt2);
+      Yvec.elements[N] = (dmt1 + dmt2) / 2.0;
+      if (SaveVectors) {
+	Rvec.elements[N] = catalog.average[i].R;
+	Dvec.elements[N] = catalog.average[i].D;
+	Zvec.elements[N] = M0;
+      }
+      N++;
+      if (N == NPTS - 1) {
+	NPTS += 2000;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+	if (SaveVectors) {
+	  REALLOCATE (Zvec.elements, float, NPTS);
+	  REALLOCATE (Rvec.elements, float, NPTS);
+	  REALLOCATE (Dvec.elements, float, NPTS);
+	}
+      }
+    }
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  REALLOCATE (Xvec.elements, float, MAX (1, N));
+  REALLOCATE (Yvec.elements, float, MAX (1, N));
+  if (SaveVectors) {
+    Rvec.Nelements = Dvec.Nelements = Zvec.Nelements = N;
+    REALLOCATE (Zvec.elements, float, MAX (1, N));
+    REALLOCATE (Rvec.elements, float, MAX (1, N));
+    REALLOCATE (Dvec.elements, float, MAX (1, N));
+  }
+
+  if (SaveVectors) {
+    free (vec1[0].elements);
+    vec1[0].elements = Yvec.elements;
+    vec1[0].Nelements = Yvec.Nelements;
+    free (vec2[0].elements);
+    vec2[0].elements = Xvec.elements;
+    vec2[0].Nelements = Xvec.Nelements;
+    free (vec3[0].elements);
+    vec3[0].elements = Zvec.elements;
+    vec3[0].Nelements = Zvec.Nelements;
+    free (vec4[0].elements);
+    vec4[0].elements = Rvec.elements;
+    vec4[0].Nelements = Rvec.Nelements;
+    free (vec5[0].elements);
+    vec5[0].elements = Dvec.elements;
+    vec5[0].Nelements = Dvec.Nelements;
+  } else {
+    graphmode.style = 2; /* set style to points */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+  }
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvo.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvo.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvo.c	(revision 21703)
@@ -0,0 +1,56 @@
+# include "dvo1.h"
+
+# define opihi_name "DVO"
+# define opihi_prompt "dvo: "
+# define opihi_description "desktop virtual observatory\n"
+# define opihi_history ".dvo"
+# define opihi_rcfile ".dvorc"
+
+/* program-dependent initialization */
+void initialize (int argc, char **argv) {
+  
+  auto_break = TRUE;
+
+  /* load the commands used by this implementation */
+  InitBasic ();
+  InitData ();
+  InitAstro ();
+  InitDVO ();
+
+  rl_readline_name = opihi_name;
+  rl_attempted_completion_function = command_completer;
+
+  set_str_variable ("HISTORY", opihi_history);
+  set_str_variable ("PROMPT", opihi_prompt);
+  set_str_variable ("RCFILE", opihi_rcfile);
+# ifdef HELPDIR_DEFAULT
+  set_str_variable ("HELPDIR", MACRO_NAME(HELPDIR_DEFAULT));
+# endif
+
+  { /* check history file permission */
+    FILE *f;
+    f = fopen (opihi_history, "a");
+    if (f == NULL) /* no current history file here */
+      fprintf (stderr, "can't save history.\n");
+    else
+      fclose (f);
+    stifle_history (200);
+    read_history (opihi_history);
+  }
+
+  signal (SIGINT, SIG_IGN);
+  return;
+}
+
+/* standard welcome message */
+void welcome () {
+  fprintf (stderr, "\n");
+  fprintf (stderr, "Welcome to %s - %s\n\n", opihi_name, opihi_description);
+}
+
+/* add program-dependent exit functions here */
+void cleanup () {
+  QuitImage ();
+  QuitGraph ();
+  return;
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvomisc.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvomisc.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/dvomisc.c	(revision 21703)
@@ -0,0 +1,142 @@
+# include "dvo1.h"
+
+void cprecess (Average *average, int Naverage, double in_epoch, double out_epoch) {
+
+  int i;
+  double T;
+  double A, D, RA, DEC, zeta, z, theta;
+  double SA, CA, SD, CD;
+  
+  T = (out_epoch - in_epoch) / 100.0;
+  
+  zeta  = RAD_DEG*(0.6406161*T + 0.0000839*T*T + 0.0000050*T*T*T);
+  theta = RAD_DEG*(0.5567530*T - 0.0001185*T*T - 0.0000116*T*T*T);
+  z     =          0.6406161*T + 0.0003041*T*T + 0.0000051*T*T*T;
+  
+  for (i = 0; i < Naverage; i++) {
+    A = average[i].R;
+    D = average[i].D;
+    SD =  cos(RAD_DEG*A + zeta)*sin(theta)*cos(RAD_DEG*D) + cos(theta)*sin(RAD_DEG*D);
+    CD = sqrt (1 - SD*SD);
+    SA =  sin(RAD_DEG*A + zeta)*cos(RAD_DEG*D)/CD;
+    CA = (cos(RAD_DEG*A + zeta)*cos(theta)*cos(RAD_DEG*D) - sin(theta)*sin(RAD_DEG*D))/CD;
+    
+    DEC = DEG_RAD*asin(SD);
+    RA  = DEG_RAD*atan2(SA, CA) + z;
+    
+    if (RA < 0)
+      RA += 360;
+    
+    average[i].R = RA;
+    average[i].D = DEC; 
+  }
+
+}
+
+/* values are ave[i].R, ave[i].D, ave[i].M */
+void sortave (Average *ave, int N) {
+
+  int l,j,ir,i;
+  Average tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = ave[l];
+    }
+    else {
+      tmp = ave[ir];
+      ave[ir] = ave[0];
+      if (--ir == 0) {
+	ave[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && ave[j].R < ave[j+1].R) j++;
+      if (tmp.R < ave[j].R) {
+	ave[i] = ave[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    ave[i] = tmp;
+  }
+}
+
+/** this does not seem to be used at the moment */
+/* values are ave[i].R, ave[i].D, ave[i].M */
+void sort_images (Image *image, int N) {
+
+  int l,j,ir,i;
+  Image tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = image[l];
+    }
+    else {
+      tmp = image[ir];
+      image[ir] = image[0];
+      if (--ir == 0) {
+	image[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && image[j].tzero < image[j+1].tzero) j++;
+      if (tmp.tzero < image[j].tzero) {
+	image[i] = image[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    image[i] = tmp;
+  }
+}
+
+/* sort subset by image[subset[i]].tzero */
+void sort_image_subset (Image *image, int *subset, int N) {
+
+  int l, j, ir, i, tmp;
+
+  if (N < 2) return;
+  l = N >> 1;
+  ir = N - 1;
+  for (;;) {
+    if (l > 0) {
+      l--;
+      tmp = subset[l];
+    }
+    else {
+      tmp = subset[ir];
+      subset[ir] = subset[0];
+      if (--ir == 0) {
+	subset[0] = tmp;
+	return;
+      }
+    }
+    i = l;
+    j = (l << 1) + 1;
+    while (j <= ir) {
+      if (j < ir && image[subset[j]].tzero < image[subset[j+1]].tzero) j++;
+      if (image[tmp].tzero < image[subset[j]].tzero) {
+	subset[i] = subset[j];
+	j += (i=j) + 1;
+      }
+      else j = ir + 1;
+    }
+    subset[i] = tmp;
+  }
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/elixir.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/elixir.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/elixir.c	(revision 21703)
@@ -0,0 +1,145 @@
+# include "dvo1.h"
+
+int WriteMsg (char *fifo, char *message);
+int ReadMsg (char *fifo, char **message);
+
+int elixir (int argc, char **argv) {
+  
+  char message[256], cmd[256], ElixirBase[256];
+  char fifo[256], fifodir[256], msgfile[256];
+  char *answer;
+  int N;
+
+  sprintf (cmd, "STATUS");
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "TIMES");
+  }
+  if ((N = get_argument (argc, argv, "-live"))) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "ALIVE");
+  }
+  if ((N = get_argument (argc, argv, "-stop"))) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "STOP");
+  }
+  if ((N = get_argument (argc, argv, "-kill"))) {
+    remove_argument (N, &argc, argv);
+    sprintf (cmd, "ABORT");
+  }
+ 
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: elixir (elixir) [-time] [-live]\n");
+    return (FALSE);
+  }
+
+  if (!VarConfig (argv[1], "%s", ElixirBase)) {
+    fprintf (stderr, "elixir %s not in config file\n", argv[1]);
+    return (FALSE);
+  }
+  sprintf (fifo, "%s.msg", ElixirBase);
+  if (!VarConfig ("FIFOS", "%s", fifodir)) {
+    fprintf (stderr, "FIFOS not in config, using local /tmp\n");
+    strcpy (fifodir, "/tmp");
+  }
+  sprintf (fifo, "%s.msg", ElixirBase);
+
+  sprintf (msgfile, "%s/EMsg.XXXXXX", fifodir);
+  mkstemp (msgfile);
+  sprintf (message, "%s %s", cmd, msgfile);
+  unlink (msgfile);
+
+  if (!WriteMsg (fifo, message)) {
+    fprintf (stderr, "can't access fifo %s\n", fifo);
+    return (FALSE);
+  }
+
+  if (ReadMsg (msgfile, &answer)) {
+    fprintf (stderr, "%s\n", answer);
+  } 
+  unlink (msgfile);
+  return (TRUE);
+  
+}
+
+int WriteMsg (char *fifo, char *message) {
+
+  int state, mode;
+  FILE *f;
+
+  /* check lockfile */
+  f = fsetlockfile (fifo, 2.0, LCK_XCLD, &state);
+  if (f == NULL) return (0);
+
+  /* write message to end of file */
+  fseek (f, 0, SEEK_END);
+  fprintf (f, "%s\n", message);
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (fifo, mode);
+
+  fclearlockfile (fifo, f, LCK_XCLD, &state);
+  return (1);
+}
+
+int ReadMsg (char *fifo, char **message) {
+
+  int i, nbytes, Nbytes, NBYTES;
+  char *buffer;
+  int state, mode;
+  FILE *f;
+  struct stat filestat;
+
+  /* wait (2 sec) for file to exist, then try to read it */
+  for (i = 0; (stat (fifo, &filestat) == -1) && (i < 20); i++) {
+    usleep (100000);
+  }
+  if (i >= 20) {
+    fprintf (stderr, "no response\n");
+    return (0);
+  }
+
+  /* check lockfile */
+  f = fsetlockfile (fifo, 2.0, LCK_XCLD, &state);
+  if (f == NULL) {
+    fprintf (stderr, "message locked (%d)\n", state);
+    return (0);
+  }
+
+  /* if file is empty, return 0 */
+  if (state == LCK_EMPTY) {
+    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    chmod (fifo, mode);
+    fclearlockfile (fifo, f, LCK_XCLD, &state);
+    return (0);
+  }  
+
+  Nbytes = 0;
+  NBYTES = 0x1000;
+  ALLOCATE (buffer, char, NBYTES);
+  while (TRUE) {
+    nbytes = fread (&buffer[Nbytes], 1, 0x1000, f);
+    if (nbytes < 0) { 
+      fprintf (stderr, "error in ReadMsg -- got -1 bytes\n");
+      return (0);
+    }
+    if (nbytes == 0) break;
+    Nbytes += nbytes;
+    NBYTES += 0x1000;
+    REALLOCATE (buffer, char, NBYTES);
+  }
+  buffer[Nbytes] = 0;
+
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (fifo, mode);
+  fclearlockfile (fifo, f, LCK_XCLD, &state);
+
+  if (Nbytes == 0) {
+    free (buffer);
+    return (0);
+  }
+
+  *message = buffer;
+  return (1);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/extract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/extract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/extract.c	(revision 21703)
@@ -0,0 +1,449 @@
+# include "dvo1.h"
+
+enum {ZERO, RA, DEC, MAG, dMAG, Xm, Xp, NMEAS, NMISS, REF, TYPE, NPHOT, NCODE, FLAG};
+
+# define NBYTES 160000
+# define BYTES_STAR 23
+# define BLOCK 1000
+# define DNSTARS 1000
+
+int extract (int argc, char **argv) {
+  
+  FILE *f;
+  int i, Col, N, Nbytes, nbytes, NPTS;
+  int InRegion, GSC, ASCII, LONEOS, mode, loadmode;
+  int j, k, m, Nregions;
+  float M0, m0;
+  char filename[128];
+  float Radius;
+  char catdir[256], gscdir[256];
+  int PhotcodeSelect;
+  char PhotCodeFile[256], code[64];
+  double ZERO_POINT;
+  int Ns, N1, n1, Nsec;
+  int Ngraph;
+  int value;
+  Vector *vec;
+  PhotCodeData photcodes;
+  Graphdata graphmode;
+  Catalog catalog;
+  RegionFile *regions;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  VarConfig ("GSCDIR", "%s", gscdir);
+
+  regions = (RegionFile *) NULL;
+  ASCII = FALSE;
+  LONEOS = TRUE;
+  GSC = FALSE;
+  if (N = get_argument (argc, argv, "-g")) {
+    remove_argument (N, &argc, argv);
+    GSC = TRUE;
+    ASCII = FALSE;
+    LONEOS = FALSE;
+  }
+
+  Col = 1;
+  if (N = get_argument (argc, argv, "-a")) {
+    remove_argument (N, &argc, argv);
+    ASCII = TRUE;
+    GSC = FALSE;
+    LONEOS = FALSE;
+    Col = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  /* check for region-based selection */
+  code = NULL;
+  PhotcodeSelect = FALSE;
+  if (N = get_argument (argc, argv, "-photcode")) {
+    PhotcodeSelect = True;
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: extract (filename) (value) [-g / -a Ncol] \n");
+    return (FALSE);
+  }
+  
+  InRegion = FALSE;
+  if (!strcmp (argv[1], "-all")) {
+    InRegion = TRUE;
+  }
+
+  /* identify selection */
+  if (LONEOS) {
+    mode = ZERO;
+    if (!strcasecmp (argv[2], "ra")) mode = RA;
+    if (!strcasecmp (argv[2], "dec")) mode = DEC;
+    if (!strcasecmp (argv[2], "mag")) mode = MAG;
+    if (!strcasecmp (argv[2], "Nmeas")) mode = NMEAS;
+    if (!strcasecmp (argv[2], "Nmiss")) mode = NMISS;
+    if (!strcasecmp (argv[2], "Xp")) mode = Xp;
+    if (!strcasecmp (argv[2], "Xm")) mode = Xm;
+    if (!strcasecmp (argv[2], "dM")) mode = dMAG;
+    if (!strcasecmp (argv[2], "flag")) mode = FLAG;
+    if (!strcasecmp (argv[2], "ref")) mode = REF;
+    if (!strcasecmp (argv[2], "type")) mode = TYPE;
+    if (!strcasecmp (argv[2], "Nphot")) mode = NPHOT;
+    if (!strcasecmp (argv[2], "Ncode")) mode = NCODE;
+    if (mode == ZERO) {
+      fprintf (stderr, "value may be one of the following:\n");
+      fprintf (stderr, " ra dec mag Nmeas Nmiss Xp Xm ID\n");
+      return (FALSE);
+    }
+  }
+
+  if ((mode == REF) && !PhotcodeSelect) {
+    fprintf (stderr, "must specify photcode for Reference\n");
+    return (FALSE);
+  }
+  if ((mode == TYPE) && !PhotcodeSelect) {
+    fprintf (stderr, "must specify photcode for Type\n");
+    return (FALSE);
+  }
+
+  /* check photcode data / selection validity */
+  Ns = -1;
+  Nsec = GetPhotcodeNsecfilt ();
+  if (PhotcodeSelect) {
+    Ns = GetPhotcodeNsec (code[0].code);
+    if ((mode != REF) && (code[0].type != PHOT_SEC) && (code[0].type != PHOT_PRI)) {
+      fprintf (stderr, "filter must be a PRIMARY or SECONDARY photometry type\n");
+      return (FALSE);
+    }
+    if ((mode == REF) && (code[0].type != PHOT_REF)) {
+      fprintf (stderr, "filter must be a REFERENCE photometry type\n");
+      return (FALSE);
+    }
+  }
+
+  if (GSC) {
+    mode = ZERO;
+    if (!strcasecmp (argv[2], "ra")) 
+      mode = RA;
+    if (!strcasecmp (argv[2], "dec")) 
+      mode = DEC;
+    if (!strcasecmp (argv[2], "mag")) 
+      mode = MAG;
+    if (mode == ZERO) {
+      fprintf (stderr, "for GSC, value may be one of the following:\n");
+      fprintf (stderr, " ra dec mag\n");
+      return (FALSE);
+    }
+  }
+
+  if ((vec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  /* create storage vector */
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+  vec[0].Nelements = N = 0;
+
+  /* we loop over Nregions, but for ASCII Nregions = 1 */
+  for (j = 0; j < Nregions; j++) {
+    
+    /* Load in data from an ASCII file list of ra, dec, mag */
+    if (ASCII) {
+      char *tbuffer;
+      double tmp;
+      float *V;
+      
+      f = fopen (argv[1], "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "ERROR: can't open data file: %s\n", argv[1]);
+	/* delete new vector! */
+	return (FALSE);
+      }
+      ALLOCATE (tbuffer, char, 1024);
+      
+      V = vec[0].elements;
+      while (scan_line (f, tbuffer) != EOF) {
+	dparse (&tmp, Col, tbuffer);
+	*V = tmp;
+	V++;
+	N++;
+	if (N == NPTS - 1) {
+	  NPTS += 1000;
+	  REALLOCATE (vec[0].elements, float, NPTS);
+	  V = &vec[0].elements[N];
+	}
+      }
+      free (tbuffer);
+      vec[0].Nelements = N;
+      REALLOCATE (vec[0].elements, float, MAX(1,N));
+      fclose (f);
+      return (TRUE);
+    }
+    
+    /* load data from the GSC files */
+    if (GSC) {
+      char *tbuffer;
+      double tmp;
+      float *V;
+      
+      if (InRegion) {
+	sprintf (filename, "%s/%s\0", gscdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s\0", gscdir, argv[1]);
+      }
+      
+      f = fopen (filename, "r");
+      if (f == (FILE *) NULL) {
+	fprintf (stderr, "no stars in %s, skipping\n", filename);
+	continue;
+      }
+      ALLOCATE (tbuffer, char, (BLOCK*BYTES_STAR));
+      
+      V = &vec[0].elements[N];
+      Nbytes = BLOCK*BYTES_STAR;
+      while ((nbytes = fread (tbuffer, 1, Nbytes, f)) > 0) {
+	for (i = 0; i < nbytes / BYTES_STAR; i++) {
+	  if (mode == RA) {
+	    dparse (&tmp, 1, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  if (mode == DEC) {
+	    dparse (&tmp, 2, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  if (mode == MAG) {
+	    dparse (&tmp, 3, &tbuffer[i*BYTES_STAR]);
+	    *V = tmp;
+	  }
+	  V++;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	    V = &vec[0].elements[N];
+	  }
+	}
+      }
+      free (tbuffer);
+      fclose (f);
+    }
+  
+    /* load data from the photometry database files */
+    if (LONEOS) {
+      /* find and open correct file */
+      if (InRegion) {
+	sprintf (filename, "%s/%s\0", catdir, regions[j].name);
+      } else {
+	sprintf (filename, "%s/%s\0", catdir, argv[1]);
+      }
+      catalog.average = (Average *) NULL;
+      catalog.measure = (Measure *) NULL;
+      catalog.secfilt = (SecFilt *) NULL;
+      loadmode = LOAD_AVES | LOAD_SECF;
+      if ((mode == REF) || (mode == TYPE) || (mode == NPHOT) || (mode == NCODE)) 
+	loadmode = loadmode | LOAD_MEAS;
+
+      /* lock, load, unlock catalog */
+      catalog.filename = filename;
+      switch (lock_catalog (&catalog, LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog);
+      case 0:
+	continue;
+      }
+      if (!load_catalog (&catalog, loadmode, TRUE)) {
+	unlock_catalog (&catalog);
+	continue;
+      }
+      unlock_catalog (&catalog);
+
+      /* assign vector values */
+      switch (mode) {
+      case (RA):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].R;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (DEC):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].D;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (MAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  M0 = (Ns == -1) ? catalog.average[i].M : catalog.secfilt[i*Nsec+Ns].M;
+	  vec[0].elements[N] = M0 / 1000.0;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NMEAS):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].Nm;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NMISS):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].Nn;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (Xp):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  /* Xp is scatter in 1/100 arcsec */
+	  vec[0].elements[N] = 0.01*catalog.average[i].Xp;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NCODE):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  Ncode = 0;
+	  for (k = 0; k < catalog.average[i].Nm; k++, m++) {
+	    if (code[0].code != GetPhotcodeEquivCodebyCode (catalog.measure[m].source)) continue;
+	    Ncode ++;
+	  }
+	  vec[0].elements[N] = Ncode;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (NPHOT):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  Ncode = 0;
+	  for (k = 0; k < catalog.average[i].Nm; k++, m++) {
+	    if (code[0].code != GetPhotcodeEquivCodebyCode (catalog.measure[m].source)) continue;
+	    if (catalog.measure[m].source & (ID_MEAS_POOR | ID_MEAS_SKIP)) continue;
+	    Ncode ++;
+	  }
+	  vec[0].elements[N] = Ncode;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (Xm):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  M0 = (Ns == -1) ? catalog.average[i].Xm : catalog.secfilt[i*Nsec+Ns].Xm;
+	  vec[0].elements[N] = (M0 == NO_MAG) ? -1.0 : pow (10.0, 0.01*M0);
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (dMAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  /* dM is 1000.0 * error */
+	  M0 = (Ns == -1) ? catalog.average[i].dM : catalog.secfilt[i*Nsec+Ns].dM;
+	  vec[0].elements[N] = (M0 == NO_MAG) ? -1.0 : 0.001*M0;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (FLAG):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  vec[0].elements[N] = catalog.average[i].code;
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (REF):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  vec[0].elements[N] = -32;
+	  for (k = 0; k < catalog.average[i].Nm; k++) {
+	    if (catalog.measure[m+k].source == N1) {
+	      vec[0].elements[N] = PhotCat (&catalog.measure[m+k]);
+	      k = catalog.average[i].Nm;
+	    }
+	  }
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      case (TYPE):
+	for (i = 0; i < catalog.Naverage; i++) {
+	  m = catalog.average[i].offset;
+	  vec[0].elements[N] = DetermineTypeCode (&catalog.average[i], &catalog.measure[m], &photcodes, N1);
+	  N++;
+	  if (N == NPTS - 1) {
+	    NPTS += 1000;
+	    REALLOCATE (vec[0].elements, float, NPTS);
+	  }
+	}
+	break;
+      }
+      if (catalog.average != 0) free (catalog.average);
+      if (catalog.measure != 0) free (catalog.measure);
+      if (catalog.secfilt != 0) free (catalog.secfilt);
+    }
+  }
+
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+  return (TRUE);
+
+}
+  
+  /* USAGE: extract (what) (where) (from) [option] */
+  /* examples:
+     extract n0000/n0001 mag m 
+     extract -g n0000/n0020 ra r 
+     extract -all Xm xm
+     extract fred dec d -a 2 */
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/find_regions.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/find_regions.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/find_regions.c	(revision 21703)
@@ -0,0 +1,156 @@
+# include "dvo1.h"
+# include "hstgsc.h"
+
+/* returns a list of region files within the desired RA, DEC region */
+RegionFile *find_regions (double Ra, double Dec, double radius, int *Nregions) {
+  
+  char filename[256];
+  char buffer[28800], temp[50];
+  RegionFile *regions;
+  FILE *f;
+  double minRa, maxRa, minDec, maxDec, rad;
+
+  double RA0, RA1, DEC0, DEC1;
+  int i, j, NBigDec;
+  int NLINES, done, NREGIONS, nregion;
+  
+  VarConfig ("GSCFILE", "%s", filename);
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find regions file %s\n", filename);
+    *Nregions = 0;
+    return ((RegionFile *) NULL);
+  }
+  
+  NREGIONS = 50;
+  ALLOCATE (regions, RegionFile, NREGIONS);
+  nregion = 0;
+
+  while (Ra < 0) Ra += 360.0;
+  while (Ra >= 360) Ra -= 360.0;
+
+  minDec = Dec - radius;
+  maxDec = Dec + radius;
+
+  if ((minDec <= -90) || (maxDec >= 90)) {
+    minRa = 0;
+    maxRa = 360;
+  } else {
+    rad = MAX (radius / (cos(minDec*RAD_DEG)), radius / (cos(maxDec*RAD_DEG)));
+    minRa = Ra - rad;
+    maxRa = Ra + rad;
+  }
+  
+  /* use the pole regions, if near pole */
+  if (maxDec > 86.25) {
+    sprintf (regions[nregion].name, "n8230/pole.cpt");
+    regions[nregion].RA0 = 0;
+    regions[nregion].RA1 = 360;
+    regions[nregion].DEC0 = 86.25;
+    regions[nregion].DEC1 = 90.0;
+    nregion ++;
+    if (nregion == NREGIONS) {
+      NREGIONS += 50;
+      REALLOCATE (regions, RegionFile, NREGIONS);
+    }
+  }
+
+  if (minDec > 86.25) {
+    return (regions);
+  }
+    
+  if ((minDec < 0) && (maxDec > 0)) {
+    /* Search Both Sides */
+    NBigDec = 0;
+  } else {
+    /* find large DEC region (directory) */
+    NBigDec = -1;
+    for (i = 0; i < 12; i++) {
+      if ((minDec >= BigDecBounds[i]) && (minDec < BigDecBounds[i+1])) {
+	NBigDec = i;
+	break;
+      }
+    }
+    if (NBigDec < 0) {
+      for (i = 13; i < 24; i++) {
+	if ((maxDec < BigDecBounds[i]) && (maxDec >= BigDecBounds[i+1])) {
+	  NBigDec = i;
+	  break;
+	}
+      }
+    }
+  }
+  if (NBigDec < 0) {
+    fprintf (stderr, "ERROR: Dec out of range: %f\n", minDec);
+    *Nregions = 0;
+    return ((RegionFile *) NULL);
+  }
+  
+  /* count lines before section */
+  NLINES = 0;
+  for (i = 0; i < NBigDec; i++) {
+    NLINES += NDecLines[i];
+  }
+  fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+  
+  /* should be in this section.  if not, there is a problem counting... */
+  /* careful with the 0,360.0 boundary **/
+  done = FALSE;
+  for (j = 0; !done && (NBigDec + j < 25); j++) {
+    fread (buffer, 48*NDecLines[NBigDec + j], 1, f);
+    for (i = 0; (i < NDecLines[NBigDec + j]); i++) {
+      strncpy (temp, &buffer[i*48], 48);
+      temp[49] = 0;
+      hstgsc_hms_to_deg (&RA0, &RA1, &DEC0, &DEC1, &temp[7]);
+      if (RA1 < RA0) RA1 += 360.0;
+      if ((DEC1 > 0) && (minDec < DEC1) && (maxDec > DEC0) && (minRa < RA1) && (maxRa > RA0)) {
+	temp[5] = 0;
+	sprintf (regions[nregion].name, "%s/%s.cpt", Dec2Sections[NBigDec + j], &temp[1]);
+	regions[nregion].RA0 = RA0;
+	regions[nregion].RA1 = RA1;
+	regions[nregion].DEC0 = DEC0;
+	regions[nregion].DEC1 = DEC1;
+	nregion ++;
+	if (nregion == NREGIONS) {
+	  NREGIONS += 50;
+	  REALLOCATE (regions, RegionFile, NREGIONS);
+	}
+      }
+      if ((DEC1 < 0) && (minDec < DEC0) && (maxDec > DEC1) && (minRa < RA1) && (maxRa > RA0)) {
+	temp[5] = 0;
+	sprintf (regions[nregion].name, "%s/%s.cpt", Dec2Sections[NBigDec + j], &temp[1]);
+	regions[nregion].RA0 = RA0;
+	regions[nregion].RA1 = RA1;
+	regions[nregion].DEC0 = DEC0;
+	regions[nregion].DEC1 = DEC1;
+	nregion ++;
+	if (nregion == NREGIONS) {
+	  NREGIONS += 50;
+	  REALLOCATE (regions, RegionFile, NREGIONS);
+	}
+      }
+      if (((DEC1 > 0) && (maxDec <= DEC1)) || ((DEC1 < 0) && (minDec >= DEC1))) {
+	done = TRUE;
+      }
+    }
+    if (done && (minDec < 0) && (maxDec > 0) && (BigDecBounds[NBigDec + j + 1] > 0)) {
+      /* skip remaining north sections, try south sections */
+      /* count lines before section */
+      NLINES = 0;
+      for (i = 0; i < 13; i++) { 
+	NLINES += NDecLines[i];
+      }
+      fseek (f, 5*2880 + 48*NLINES, SEEK_SET);
+      done = FALSE;
+      j = 12;
+    }
+  }
+
+  REALLOCATE (regions, RegionFile, MAX(1,nregion));
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (regions);
+  
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/fitcolors.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/fitcolors.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/fitcolors.c	(revision 21703)
@@ -0,0 +1,225 @@
+# include "dvo1.h"
+# define NMIN_PTS 100
+
+void init_catalog (Catalog *catalog);
+void free_catalog (Catalog *catalog, int Ncatalog);
+
+/* this function takes a photcode (and camera name?) and measures the  *
+ * chip-to-chip slopes for all DEP photcodes equiv to the PRI/SEC code */
+
+int fitcolors (int argc, char **argv) {
+  
+  int *list, Nlist;
+  int i, k, m, NP1, NP2, NP, Np, Npts, NPTS;
+  int N1, N2, i1, i2, mode[4];
+  int Nsec, Nregions, status;
+  char catdir[256], filename[256], *RegionName, *RegionList;
+  char *cmd, *outcmd, *camera;
+  double *M1, *M2;
+  float *out;
+
+  Catalog *catalog;
+  RegionFile *regions;
+  PhotCode **codelist, *tcode, *code[4];
+  Vector *xvec, *yvec;
+  Buffer *buf;
+
+  /* defaults */
+  regions  = NULL;
+  catalog  = NULL;
+  codelist = NULL;
+  xvec = yvec = NULL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 1)) goto usage;
+
+  /* interpret command-line options */
+  if (argc != 4) goto usage;
+
+  /* determine relevant photcodes, colors */
+  if (!(Np = GetPhotcodeCodebyName (argv[2]))) {
+    fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+    return (FALSE);
+  }
+  camera = argv[3];
+
+  /* reduce the list of codes */
+  list = GetPhotcodeEquivList (Np, &Nlist);
+  ALLOCATE (codelist, PhotCode *, Nlist);
+  for (i = NP = 0; i < Nlist; i++) {
+    tcode = GetPhotcodebyCode (list[i]);
+    if (strncmp (tcode[0].name, camera, strlen(camera))) continue;
+    codelist[NP] = tcode;
+    NP++;
+  }
+  mode[0] = mode[1] = MAG_REL;  /* we should be applying any relative photometry corrections here */
+  mode[2] = mode[3] = MAG_AVE;
+  /* set the reference colors */
+  code[2] = GetPhotcodebyCode (codelist[0][0].c1);
+  code[3] = GetPhotcodebyCode (codelist[0][0].c2);
+  /* all codes must have the same colors (validate) */
+  for (i = 0; i < NP; i++) {
+    if (codelist[i][0].c1 != codelist[0][0].c1) goto color_mismatch;
+    if (codelist[i][0].c2 != codelist[0][0].c2) goto color_mismatch;
+  }
+  fprintf (stderr, "using %d photcodes\n", NP);
+
+  /* output is a named buffer */
+  if ((buf = SelectBuffer (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  buf[0].matrix.Naxis[0] = NP;
+  buf[0].matrix.Naxis[1] = NP;
+
+  /* I should encapsulate this in a create_default_buffer */
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+  buf[0].header.bitpix = buf[0].bitpix = -32;
+  buf[0].header.unsign = buf[0].unsign = FALSE;
+  buf[0].header.bscale = buf[0].bscale = 1.0;
+  buf[0].header.bzero  = buf[0].bzero  = 0.0;
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = NP;
+  buf[0].header.Naxis[1] = NP;
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+  out = (float *) buf[0].matrix.buffer;
+  /* we set a default flag value of -1 */
+  for (i = 0; i < NP*NP; i++) {
+    out[i] = -1;
+  }
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+
+  /* loop over regions, extract data for each region */
+  ALLOCATE (catalog, Catalog, Nregions);
+  for (k = 0; k < Nregions; k++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[k].name);
+    catalog[k].filename = filename;
+    switch (lock_catalog (&catalog[k], LCK_SOFT)) {
+      case 2:
+	unlock_catalog (&catalog[k]);
+      case 0:
+	catalog[k].Naverage = 0;
+	continue;
+    }
+    if (!load_catalog (&catalog[k], LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+      catalog[k].Naverage = 0;
+      unlock_catalog (&catalog[k]);
+      continue;
+    }
+    unlock_catalog (&catalog[k]);
+  }
+  fprintf (stderr, "using %d regions\n", Nregions);
+
+  /* vectors to save data */
+  Npts = 0;
+  NPTS = 1;
+  if ((xvec = SelectVector ("tmp_x", ANYVECTOR, TRUE)) == NULL) goto escape;
+  if ((yvec = SelectVector ("tmp_y", ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  /*** generate the color-color vectors for the pairs ***/
+  /* loop over chip photcode pairs */
+  for (NP1 = 0; NP1 < NP; NP1++) {
+    for (NP2 = NP1 + 1; NP2 < NP; NP2++) {
+      code[0] = codelist[NP1];
+      code[1] = codelist[NP2];
+      
+      /* extract all magnitude pairs from catalog tables */
+      Npts = 0;
+      for (k = 0; k < Nregions; k++) {
+	if (catalog[k].Naverage == 0) continue;
+
+	/* get correct mags, convert to X,Y */
+	for (i = 0; i < catalog[k].Naverage; i++) {
+	  M1 = M2 = NULL;
+	  m = catalog[k].average[i].offset;
+
+	  M1 = ExtractDMag (&code[0], &mode[0], &catalog[k].average[i], &catalog[k].secfilt[i*Nsec], &catalog[k].measure[m], &N1);
+	  if (N1 == 0) goto skip_star;
+
+	  M2 = ExtractDMag (&code[2], &mode[2], &catalog[k].average[i], &catalog[k].secfilt[i*Nsec], &catalog[k].measure[m], &N2);
+	  if (N2 == 0) goto skip_star;
+
+	  for (i1 = 0; i1 < N1; i1++) {
+	    for (i2 = 0; i2 < N2; i2++) {
+	      yvec[0].elements[Npts] = M1[i1];
+	      xvec[0].elements[Npts] = M2[i2];
+	      Npts++;
+	      if (Npts >= NPTS) {
+		NPTS += 2000;
+		REALLOCATE (xvec[0].elements, float, NPTS);
+		REALLOCATE (yvec[0].elements, float, NPTS);
+	      }
+	    }
+	  }
+	skip_star:
+	  if (M1 != NULL) free (M1);
+	  if (M2 != NULL) free (M2);
+	}
+      }
+
+      if (Npts < NMIN_PTS) continue;
+      xvec[0].Nelements = Npts;
+      yvec[0].Nelements = Npts;
+
+      /* perform robust fit on dmag vs color */
+      cmd = strcreate ("fit tmp_x tmp_y 1 -clip 3 3 -quiet");
+      status = command (cmd, &outcmd);
+      if (outcmd != NULL) free (outcmd);
+      
+      /* do something useful with the results (stored in Cn, C0, C1, etc) */
+      fprintf (GetOutfile(), "%s - %s : ", code[0][0].name, code[1][0].name);
+      fprintf (GetOutfile(), "%7.4f %7.4f   %7.4f   ", 
+	       get_double_variable ("C0"), get_double_variable ("C1"), get_double_variable ("dC"));
+      fprintf (GetOutfile(), "%5s of %5d\n", get_variable ("Cnv"), Npts);
+      out[NP1 + NP2*NP] = get_double_variable ("C1");
+    }
+  }
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: chipcolors (output) (photcode) (camera)\n");
+  goto escape;
+
+color_mismatch:
+  fprintf (stderr, "error: all chips must have the same colors\n");
+
+escape:
+  if (regions != NULL) free (regions);
+  if (codelist != NULL) free (codelist);
+  DeleteVector (xvec);
+  DeleteVector (yvec);
+  free_catalog (catalog, Nregions);
+  return (FALSE);
+}
+
+void free_catalog (Catalog *catalog, int Ncatalog) {
+
+  int i;
+
+  if (catalog == NULL) return;
+  for (i = 0; i < Ncatalog; i++) {
+    if (catalog[i].average != NULL) free (catalog[i].average);
+    if (catalog[i].secfilt != NULL) free (catalog[i].secfilt);
+    if (catalog[i].measure != NULL) free (catalog[i].measure);
+  }
+  free (catalog);
+}
+
+void init_catalog (Catalog *catalog) {
+  catalog[0].average = NULL; 
+  catalog[0].secfilt = NULL;
+  catalog[0].measure = NULL;
+  catalog[0].Naverage = 0; 
+  catalog[0].Nsecfilt = 0;
+  catalog[0].Nmeasure = 0;
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gcat.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gcat.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gcat.c	(revision 21703)
@@ -0,0 +1,42 @@
+# include "dvo1.h"
+
+int gcat (int argc, char **argv) {
+  
+  int i, Nregions;
+  RegionFile *regions;
+  char filename[128];
+  struct stat filestat;
+  double Ra, Dec, Radius;
+  char catdir[256];
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  if ((argc != 3) && (argc != 4)) {
+    fprintf (stderr, "USAGE: gcat RA DEC [Radius]\n");
+    return (FALSE);
+  }
+
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  if (argc == 4) 
+    Radius = atof(argv[3]);
+  else 
+    Radius = 0.0001;
+
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    if (stat (filename, &filestat) != -1) {
+      fprintf (stderr, "%3d %s *\n", i, regions[i].name);
+    } else {
+      fprintf (stderr, "%3d %s\n", i, regions[i].name);
+    } 
+    set_str_variable ("CATNAME", regions[i].name);
+  }
+
+  return (TRUE);
+  free (regions);
+
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/get_regions.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/get_regions.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/get_regions.c	(revision 21703)
@@ -0,0 +1,50 @@
+# include "dvo1.h"
+
+/* return region files containing given image */
+GSCRegion *get_regions (Image *image, int *Nregions) {
+  
+  GSCRegion *region;
+  FILE *f;
+  double x, y;
+  double dec, ra;
+  int j, done, nregion, NREGION;
+  char filename[256], path[256];
+  
+  VarConfig ("CATDIR", "%s", path);
+  VarConfig ("GSCFILE", "%s", filename);
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find GSC region file %s\n", filename);
+    exit (0);
+  }
+  
+  /* find regions at image corners */
+  NREGION = 10;
+  ALLOCATE (region, GSCRegion, NREGION);
+  nregion = 0;
+
+  /* look for new regions on grid across image */ 
+  for (x = 0.0; x <= 1.0; x+=0.25) {
+    for (y = 0.0; y <= 1.0; y+=0.25) {
+      XY_to_RD (&ra, &dec, image[0].NX*(1.1*x - 0.05), image[0].NY*(1.1*y - 0.05), &image[0].coords);
+      aregion (&region[nregion], f, ra, dec, path);
+      done = FALSE;
+      for (j = 0; (j < nregion) && !done; j++) {
+	if (!strcmp (region[nregion].filename, region[j].filename)) {
+	  nregion --;
+	  done = TRUE;
+	}
+      }
+      nregion ++;
+      if (nregion == NREGION) {
+	NREGION += 10;
+	REALLOCATE (region, GSCRegion, NREGION);
+      }
+    }
+  }
+  *Nregions = nregion;
+  
+  fclose (f);
+  return (region);
+  
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/getxtra.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/getxtra.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/getxtra.c	(revision 21703)
@@ -0,0 +1,63 @@
+# include "dvo1.h"
+
+int getxtra (int argc, char **argv) {
+  
+  SelectXtra = (char *) NULL;
+  if (N = get_argument (argc, argv, "-xtra")) {
+    SelectXtra = TRUE;
+    remove_argument (N, &argc, argv);
+    XtraType = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+    XtraValue = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  SelectRegion = (char *) NULL;
+  if (N = get_argument (argc, argv, "-region")) {
+    SelectRegion = TRUE;
+    remove_argument (N, &argc, argv);
+    RA = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+    Dec = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+    Radius = atof (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Mode = (char *) NULL;
+  if (N = get_argument (argc, argv, "-mode")) {
+    remove_argument (N, &argc, argv);
+    Mode = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+  Range = (char *) NULL;
+  if (N = get_argument (argc, argv, "-range")) {
+    remove_argument (N, &argc, argv);
+    Range = strcreate (atof[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    fprintf (stderr, "USAGE: addxtra R D radius (type) (value)\n");
+    return (FALSE);
+  }
+  
+  
+
+  /*
+
+  validate the input values (type, defines the needed options)
+  find catalog (based on r,d)
+  load catalog (need to load measures?)
+  find the object
+  find the xtra entry (sorted by ra/dec? sorted by averef?)
+  add new entry
+  save catalog 
+  */
+}
+
+/* 
+   get specified values for specified objects 
+
+   getxtra type -xtra name K01.01 
+   getxtra type -region R D radius 
+
+*/
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gimages.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gimages.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gimages.c	(revision 21703)
@@ -0,0 +1,133 @@
+# include "dvo1.h"
+
+int gimages (int argc, char **argv) {
+  
+  int i, j, N, Nimage, Nfound, *subset, Nsubset, status;
+  double ra, dec, Ra, Dec, X, Y, Mcal;
+  double trange, t;
+  int TimeSelect, PixelCoords, TimeFormat, PhotCodeSelect;
+  time_t tzero, TimeReference;
+  char name[64], *date;
+
+  PhotCode *code;
+  Image *image;
+
+  if (!InitPhotcodes ()) return (FALSE);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-tref"))) {
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+
+    t = atof (argv[N]);
+    tzero = TimeRef (t, TimeReference, TimeFormat);
+    remove_argument (N, &argc, argv);
+
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  code = NULL;
+  PhotCodeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    PhotCodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  PixelCoords = FALSE;
+  if ((N = get_argument (argc, argv, "-pix"))) {
+    remove_argument (N, &argc, argv);
+    PixelCoords = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: gimages RA DEC [-time t dt] [-pix]\n");
+    return (FALSE);
+  }
+
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TimeSelect);
+  BuildChipMatch (image, Nimage);
+
+  Nfound = 0;
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    if (PhotCodeSelect) {
+      if ((code[0].type == PHOT_REF) || (code[0].type == PHOT_DEP)) {
+	if (code[0].code != image[i].source) continue;
+      } 
+      if ((code[0].type == PHOT_PRI) || (code[0].type == PHOT_SEC)) {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (image[i].source)) continue;
+      } 
+    }      
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+
+    status = RD_to_XY (&X, &Y, Ra, Dec, &image[i].coords);
+    if (!status) continue;
+    if (X < 0) continue;
+    if (Y < 0) continue;
+    if (X > image[i].NX) continue;
+    if (Y > image[i].NY) continue;
+
+    Mcal = applyMcal (&image[i], 2048.0, 2048.0);
+    date = sec_to_date (image[i].tzero);
+
+    if (PixelCoords) {
+      fprintf (GetOutfile(), "%3d %s %6.1f %6.1f %20s %5d %2d %4.2f %6.3f %5.3f %5.3f %4x\n", 
+	       Nfound, image[i].name, X, Y, date, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*Mcal, 0.001*image[i].dMcal, image[i].exptime, image[i].code);
+    } else {
+      XY_to_RD (&ra, &dec, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+      fprintf (GetOutfile(), "%3d %s %8.4f %8.4f %20s %5d %2d %4.2f %6.3f %5.3f %5.3f %4x\n", 
+	       Nfound, image[i].name, ra, dec, date, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*Mcal, 0.001*image[i].dMcal, image[i].exptime, image[i].code);
+    }
+    sprintf (name, "IMAGEx:%d", Nfound);
+    set_variable     (name, X);
+    sprintf (name, "IMAGEy:%d", Nfound);
+    set_variable     (name, Y);
+    sprintf (name, "IMAGEt:%d", Nfound);
+    set_str_variable (name, date);
+    sprintf (name, "IMAGEccd:%d", Nfound);
+    set_int_variable (name, image[i].ccdnum);
+    sprintf (name, "IMAGEname:%d", Nfound);
+    set_str_variable (name, image[i].name);
+    Nfound ++;
+    free (date);
+  }
+  set_int_variable ("IMAGEx:n", Nfound);
+  set_int_variable ("IMAGEy:n", Nfound);
+  set_int_variable ("IMAGEt:n", Nfound);
+  set_int_variable ("IMAGEccd:n", Nfound);
+  set_int_variable ("IMAGEname:n", Nfound);
+
+  free (image);
+  free (subset);
+
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gstar.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gstar.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/gstar.c	(revision 21703)
@@ -0,0 +1,215 @@
+# include "dvo1.h"
+
+void print_value (FILE *f, double value, short int ival);
+
+int gstar (int argc, char **argv) {
+  
+  char filename[128], catdir[256], *date;
+  double Ra, Dec, Radius, Radius2, r, dec0, dec1;
+  double Mcat, Mrel;
+  float *RA, *DEC;
+  int i, j, k, m, N, *N1, Nregions, Nsec, NPTS;
+  int Nstars, found, GetMeasures, Nlo, Nhi;
+  int SaveVectors;
+  Vector *vec1, *vec2, *vec3, *vec4;
+  RegionFile *regions;
+  Catalog catalog;
+  PhotCode *code;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  NPTS = 0;
+  vec1 = vec2 = vec3 = vec4 = NULL;
+  SaveVectors = FALSE;
+  if ((N = get_argument (argc, argv, "-save"))) {
+    remove_argument (N, &argc, argv);
+    SaveVectors = TRUE;
+    if ((vec1 = SelectVector ("gs:m", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec2 = SelectVector ("gs:t", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec3 = SelectVector ("gs:z", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    if ((vec4 = SelectVector ("gs:f", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  }
+
+  GetMeasures = FALSE;
+  if ((N = get_argument (argc, argv, "-m"))) {
+    GetMeasures = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: gstar RA DEC Radius [-m]\n");
+    return (FALSE);
+  }
+  
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  Radius = atof (argv[3]);
+
+  while (Ra < 0.0) Ra += 360.0;
+  while (Ra > 360.0) Ra -= 360.0;
+  
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* set filename, read in header */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  /* lock, load, unlock catalog */
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, float, Nstars);
+  ALLOCATE (DEC, float, Nstars);
+  ALLOCATE (N1, int, Nstars);
+
+  /* find star(s) in RA, DEC list -- use a dumb algorithm for now, improve later */
+  /* stars are not guaranteed to be sorted in RA or in DEC, so first sort the list */
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    N1[i] = i;
+  }
+  /* sort list by DEC */
+  if (Nstars > 1) sort_lists (DEC, RA, N1, Nstars);
+  /* at this point, RA, DEC, and N1 are sorted by DEC.  
+     catalog.average[N1[i]].R = RA[i] */
+
+  /* bracket the RA range of interest */
+  dec0 = Dec - Radius;
+  dec1 = Dec + Radius;
+
+  Nlo = 0; Nhi = catalog.Naverage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (DEC[N] < dec0) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  /* DEC[Nlo] is guaranteed to be just lower than dec0 */
+
+  Radius2 = Radius*Radius;
+  found = FALSE;
+
+  /* data has been loaded, get ready to plot it */
+  if (SaveVectors) {
+    N = 0;
+    NPTS = 1000;
+    ALLOCATE (vec1[0].elements, float, NPTS);
+    ALLOCATE (vec2[0].elements, float, NPTS);
+    ALLOCATE (vec3[0].elements, float, NPTS);
+    ALLOCATE (vec4[0].elements, float, NPTS);
+  }
+
+  for (i = Nlo; (i < catalog.Naverage) && !found; i++) {
+
+    if (dec0 > DEC[i]) continue;
+    if (dec1 < DEC[i]) found = TRUE;
+    
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      k = N1[i];
+      fprintf (GetOutfile(), "star: %d\n", k);
+      fprintf (GetOutfile(), "%9.5f %9.5f %3d of %3d  %4.1f %5d\n", catalog.average[k].R, catalog.average[k].D, 
+	       catalog.average[k].Nm, catalog.average[k].Nn + catalog.average[k].Nm,
+	       0.01*catalog.average[k].Xp, catalog.average[k].code);
+      
+      /* filter names -- primary code is 0 in this function */
+      for (j = 0; j < Nsec + 1; j++) {
+	code = GetPhotcodebyNsec (j);
+	fprintf (GetOutfile (), "%s ", code[0].name);
+      }
+      fprintf (GetOutfile (), "\n");
+
+      /* average mags */
+      print_value (GetOutfile(), 0.001*catalog.average[k].M, catalog.average[k].M);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), 0.001*catalog.secfilt[j + Nsec*k].M, catalog.secfilt[j + Nsec*k].M);
+      fprintf (GetOutfile(), "\n");
+
+      /* average mag errors */
+      print_value (GetOutfile(), 0.001*catalog.average[k].dM, catalog.average[k].dM);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), 0.001*catalog.secfilt[j + Nsec*k].dM, catalog.secfilt[j + Nsec*k].dM);
+      fprintf (GetOutfile(), "\n");
+
+      /* average mag chisq */
+      print_value (GetOutfile(), pow (10.0, 0.01*catalog.average[k].Xm), catalog.average[k].Xm);
+      for (j = 0; j < Nsec; j++) print_value (GetOutfile(), pow (10.0, 0.01*catalog.secfilt[j + Nsec*k].Xm), catalog.secfilt[j + Nsec*k].Xm);
+      fprintf (GetOutfile(), "\n");
+
+      if (GetMeasures || SaveVectors) {
+	m = catalog.average[k].offset;
+	for (j = 0; j < catalog.average[k].Nm; j++, m++) {
+
+	  Mcat = PhotCat (&catalog.measure[m]);
+	  Mrel = PhotRel (&catalog.measure[m], &catalog.average[k], &catalog.secfilt[k*Nsec]);
+
+	  if (GetMeasures) {
+	    date = sec_to_date (catalog.measure[m].t);
+	    fprintf (GetOutfile(), "%6.3f %6.3f %5.3f  %20s  %5.2f %5.2f %2d %3x %3d %-20s\n", 
+		     Mcat, Mrel, 0.001*catalog.measure[m].dM,
+		     date, 0.01*catalog.measure[m].dR, 0.01*catalog.measure[m].dD,
+		     catalog.measure[m].dophot, catalog.measure[m].flags,
+		     catalog.measure[m].source, GetPhotcodeNamebyCode (catalog.measure[m].source));
+	    free (date);
+	  }
+	  
+	  if (SaveVectors) {
+	    vec1[0].elements[N] = Mcat;
+	    vec2[0].elements[N] = catalog.measure[m].t;
+	    vec3[0].elements[N] = 0.001*catalog.measure[m].airmass;
+	    vec4[0].elements[N] = catalog.measure[m].source;
+	    N ++;
+	    if (N == NPTS - 1) {
+	      NPTS += 2000;
+	      REALLOCATE (vec1[0].elements, float, NPTS);
+	      REALLOCATE (vec2[0].elements, float, NPTS);
+	      REALLOCATE (vec3[0].elements, float, NPTS);
+	      REALLOCATE (vec4[0].elements, float, NPTS);
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  if (SaveVectors) {
+    vec1[0].Nelements = N;
+    vec2[0].Nelements = N;
+    vec3[0].Nelements = N;
+    vec4[0].Nelements = N;
+  }
+
+  free (RA);
+  free (DEC);
+  free (N1);
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+  if (catalog.secfilt != 0) free (catalog.secfilt);
+
+  return (TRUE);
+
+}
+
+
+void print_value (FILE *f, double value, short int ival) {
+  if (ival == NO_MAG) 
+    fprintf (f, "NaN    ");
+  else 
+    fprintf (f, "%6.3f ", value);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/Photometry
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/Photometry	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/Photometry	(revision 21703)
@@ -0,0 +1,26 @@
+
+cals: Plot residuals for reference stars. 
+
+ This function takes the currently displayed region and looks for all
+ stars which have 'reference' photometry and plots the difference
+ between the reference magnitude (in the given filter) and the
+ observed magnitude (same filter) versus one of several options:  the
+ star color (based on the 'reference' photometry), the star magnitude,
+ the airmass, time, secqunce, etc.
+
+ These plots can use one of two options for the 'observed' magnitude.
+ Either, the magnitude for individual measurement, using the currently
+ set values for the CCD zeropoints (from the photometry database), or
+ using the relative photometry determined for the particular star.  
+
+
+dmags: plot difference between two measured magnitudes
+
+resid: 
+
+abszero
+
+zeropts
+
+cmd
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/catalog
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/catalog	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/catalog	(revision 21703)
@@ -0,0 +1,74 @@
+
+  catalog (filename/-all) [many options!]
+
+  plot the star positions from any of several possible catalogs.  By
+default, the photometry database (see Database) is used, but the HST
+Guide Star Catalog and a simple ASCII file may also be used.  The
+plotting is done on window 0, with the current point type.  The point
+size can be scaled by the magnitude of the star or by the number
+of observations (-n).  
+
+There are many options to this function.  Here they are all:
+
+-e epoch: given ASCII catalog has this epoch, plot in J2000
+
+-ID ID: plot only measurements with this ID number
+ ID may be one of:
+	0 - star
+	4 - variable
+	5 - transient
+      100 - ghost image
+      101 - trail (satellite)
+      102 - bright star garbage	
+      note that numbers < 50 are static objects, 
+	and numbers > 100 are bad data.
+
+-all:  plot all data for the current display region
+
+-g: use the HST GSC instead of the photometry database
+
+-a RA DEC MAG:  the given file is an ASCII file with 
+	RA, DEC, and MAG in columns given by the three numbers
+
+-v ra dec scale: save the values in vectors with the three names given
+	the ra and dec are always used, but the third is the size of 
+	the points plotted, based on whatever the scaling is.
+
+-m m1 m2: scale points by magnitude, with smallest points having
+	magnitude m2.
+
++n n1 n2: scale points by number of measurements, with smallest points
+	having number n1.
+
+-n n1 n2: scale points by number of missing values, with smallest points
+	having number n1.
+
+Note that if two of -m, -n, +n are given, the first determines the
+ scaling of the points.  the second provides an allowed range, so
+ points are only plotted if the second parameter has a value in the
+ given range.
+
+Examples: 
+
+  catalog -all -m 12 18  
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest.
+   
+  catalog -all -m 12 18 +n 2 4
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest, but only
+    if the stars have 2-4 measurements each
+   
+  catalog -all -m 12 18 +n 0 1 -ID 101
+    plot all stars in current region with magnitude 12 having the
+    biggest points and magnitude 18 having the smallest, but only
+    if the stars have 1 measurements each, and if the object is 
+    found to be a trail.
+   
+  catalog n2230/1819.cpt -n 2 8  
+    plot all stars in catalog n2230/1819.cpt with the biggest points
+    having 8 measurements and the smallest having only 2.
+
+  See Also: lcat, pcat, style, region
+
+   
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/images
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/images	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/images	(revision 21703)
@@ -0,0 +1,9 @@
+
+  images 
+
+  plot the outlines of images in the photometry database and list
+  along with relevant information.  An example of relevant data is the
+  image time, which can be used in other functions to define a specific
+  image or a range of images relevant for the function.
+
+  See also: Database, lcat, pcat
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/imstats
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/imstats	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/imstats	(revision 21703)
@@ -0,0 +1,5 @@
+
+  imstats 
+
+  list interesting statistics for a set of images.
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcat
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcat	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcat	(revision 21703)
@@ -0,0 +1,10 @@
+
+  lcat [-all]
+
+  list photometry database files in the current region.  if the option
+  -all is given, all database in the region are listed, along with a
+  comment to show if there is data in the file or not.  if the option
+  is not given, only those files with data are listed.
+
+  See also: region, pcat
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcurve
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcurve	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/lcurve	(revision 21703)
@@ -0,0 +1,8 @@
+
+  lcurve RA DEC Radius [-l]
+
+  plot light curves for all stars within Radius of the given
+  coordinates.  The units for all three are decimal degrees.  
+  The option -l autoscales the limits of the plot.  
+
+  See also: limits
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/mextract
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/mextract	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/mextract	(revision 21703)
@@ -0,0 +1,12 @@
+
+ mextract (filename) (value) [-g / -a Ncol]
+
+ extracts a vector from the photometry database.  The name also
+ specifies the type of data extracted (and is case insensitive).  Only
+ certain names may be used.
+
+ The possible values are:
+ ra, dec, mag, dmag, Mcal, Mrel, source, time, dR, dD
+
+
+ Note: this routine extracts the individual measurements.
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/pcat
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/pcat	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/pcat	(revision 21703)
@@ -0,0 +1,9 @@
+
+  pcat [-all]
+
+  plot outlines of photometry database files in the current region.
+  if the option -all is given, all database in the region are listed.
+  if the option is not given, only those files with data are listed.
+
+  See also: region, lcat
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/resid
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/resid	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/resid	(revision 21703)
@@ -0,0 +1,12 @@
+
+  resid [-im time] [-X] [-l] (photometry file)
+
+  plot the photometry residuals for a photometry database file. 
+  For every star in the database, the average magnitude is plotted 
+  vs the difference between the average magnitude and each existing 
+  measurement for that star.  
+
+  -l		automatically set the plot limits.
+  -X		plot residual divided by photometric error
+  -im time	only plot the residuals for one of the images 
+		in the database, specified by the obseravation time.
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/simage
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/simage	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/help/simage	(revision 21703)
@@ -0,0 +1,7 @@
+
+  simage (filename)
+
+  plot the positions of stars in a CMP file.  This function is a
+  useful test for image comparisons, and astrometry must be determined
+  before the function is run.
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/images.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/images.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/images.c	(revision 21703)
@@ -0,0 +1,164 @@
+# include "dvo1.h"
+
+int images (int argc, char **argv) {
+
+  int i, j, Nimage, status, InPic, leftside, *plist, TimeSelect, ByName;
+  time_t tzero, tend;
+  int N, NPTS, n, npts;
+  Vector Xvec, Yvec;
+  double r, d, x[4], y[4], Rmin, Rmax, Rmid, trange;
+  Image *image;
+  Graphdata graphmode;
+  char name[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  ByName = FALSE;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    ByName = TRUE;
+  }
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-trange"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image [-time start range]\n");
+    return (FALSE);
+  }
+  
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  Rmin = graphmode.coords.crval1 - 180.0;
+  Rmax = graphmode.coords.crval1 + 180.0;
+  Rmid = 0.5*(Rmin + Rmax);
+  
+  npts = NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  ALLOCATE (plist, int, NPTS);
+  n = N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (ByName && strcmp (name, image[i].name)) continue;
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+
+    /* project this image to screen display coords */
+    /* DIS images represent a field, not a chip */
+    if (!strcmp(&image[i].coords.ctype[4], "-DIS")) {
+      x[0] = -0.5*image[i].NX; y[0] = -0.5*image[i].NY;
+      x[1] = +0.5*image[i].NX; y[1] = -0.5*image[i].NY;
+      x[2] = +0.5*image[i].NX; y[2] = +0.5*image[i].NY;
+      x[3] = -0.5*image[i].NX; y[3] = +0.5*image[i].NY;
+    } else {
+      x[0] = 0;           y[0] = 0;
+      x[1] = image[i].NX; y[1] = 0;
+      x[2] = image[i].NX; y[2] = image[i].NY;
+      x[3] = 0;           y[3] = image[i].NY;
+    }
+    status = FALSE;
+
+    leftside = FALSE;
+    for (j = 0; j < 4; j++) {
+      XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+      while (r < Rmin) { r += 360.0; }
+      while (r > Rmax) { r -= 360.0; }
+      if (j == 0) {
+	leftside = (r < Rmid);
+      } 
+      if (j > 0) { 
+	if ( leftside && (r > Rmid + 90)) { r -= 360.0; }
+	if (!leftside && (r < Rmid - 90)) { r += 360.0; }
+      }
+      status |= fRD_to_XY (&Xvec.elements[N+2*j], &Yvec.elements[N+2*j], r, d, &graphmode.coords);
+      if (j > 0) {
+	Xvec.elements[N+2*j - 1] = Xvec.elements[N+2*j];
+	Yvec.elements[N+2*j - 1] = Yvec.elements[N+2*j];
+      }
+    }
+    Xvec.elements[N+7] = Xvec.elements[N];
+    Yvec.elements[N+7] = Yvec.elements[N];
+    InPic = FALSE;
+    for (j = 0; j < 8; j+=2) {
+      if ((Xvec.elements[N+j] >= graphmode.xmin) && 
+	  (Xvec.elements[N+j] <= graphmode.xmax) && 
+	  (Yvec.elements[N+j] >= graphmode.ymin) && 
+	  (Yvec.elements[N+j] <= graphmode.ymax))
+	InPic = TRUE;
+    }
+    if (InPic && status) {
+      plist[n] = i;
+      n++;
+      if (n > npts - 1) {
+	npts += 200;
+	REALLOCATE (plist, int, npts);
+      }
+      N+=8;
+      if (N > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  fprintf (stderr, "plotting %d images\n", N/8);
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (image);
+  return (TRUE);
+
+}
+
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imbox.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imbox.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imbox.c	(revision 21703)
@@ -0,0 +1,95 @@
+# include "dvo1.h"
+
+int imbox (int argc, char **argv) {
+  
+  int i, j, status, InPic, flipped, Nextend;
+  Vector Xvec, Yvec;
+  double r, d, x[4], y[4], Rmin, Rmax, Rmid;
+  Header header;
+  Coords coords;
+  Graphdata graphmode;
+  int Ngraph;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imbox (filename)\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (!fits_read_header (argv[1], &header)) {
+    fprintf (stderr, "file not found\n");
+    return (FALSE);
+  }
+  
+  Nextend = 0;
+  if (header.Naxes == 0) {
+    fits_scan (&header, "NEXTEND", "%d", 1, &Nextend);
+  }
+  
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+  Rmid = 0.5*(Rmin + Rmax);
+  
+  /* project this image to screen display coords */
+  ALLOCATE (Xvec.elements, float, 8);
+  ALLOCATE (Yvec.elements, float, 8);
+
+  for (i = Nextend ? 0 : -1; i < Nextend; i++) {
+    if (Nextend) {
+      fits_read_Xheader (argv[1], &header, i);
+    }
+    if (!GetCoords (&coords, &header)) {
+      fprintf (stderr, "can't get WCS info from header\n");
+      return (TRUE);
+    }
+    x[0] = 0;               y[0] = 0;
+    x[1] = header.Naxis[0]; y[1] = 0;
+    x[2] = header.Naxis[0]; y[2] = header.Naxis[1];
+    x[3] = 0;               y[3] = header.Naxis[1];
+    status = FALSE;
+    flipped = FALSE;
+    for (j = 0; j < 4; j++) {
+      XY_to_RD (&r, &d, x[j], y[j], &coords);
+      while ((j == 0) && (r < Rmin)) { flipped = TRUE; r += 360.0; }
+      while ((j == 0) && (r > Rmax)) { flipped = TRUE; r -= 360.0; }
+      if ((j > 0) && flipped) {
+	while (r < Rmid) r+= 360.0;
+	while (r > Rmid) r-= 360.0;
+      }
+      status |= fRD_to_XY (&Xvec.elements[2*j], &Yvec.elements[2*j], r, d, &graphmode.coords);
+      if (j > 0) {
+	Xvec.elements[2*j - 1] = Xvec.elements[2*j];
+	Yvec.elements[2*j - 1] = Yvec.elements[2*j];
+      }
+    }
+    Xvec.elements[7] = Xvec.elements[0];
+    Yvec.elements[7] = Yvec.elements[0];
+    InPic = FALSE;
+    for (j = 0; j < 8; j+=2) {
+      if ((Xvec.elements[j] >= graphmode.xmin) && 
+	  (Xvec.elements[j] <= graphmode.xmax) && 
+	  (Yvec.elements[j] >= graphmode.ymin) && 
+	  (Yvec.elements[j] <= graphmode.ymax))
+	InPic = TRUE;
+    }
+
+    Xvec.Nelements = Xvec.Nelements = 8;
+    if (InPic) {
+      graphmode.style = 2; /* points */
+      graphmode.ptype = 100; /* connect pairs of points */
+      graphmode.etype = 0;
+      PrepPlotting (8, &graphmode);
+      PlotVector (8, Xvec.elements);
+      PlotVector (8, Yvec.elements);
+    }
+  }
+
+  fits_free_header (&header);
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
+
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdata.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdata.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdata.c	(revision 21703)
@@ -0,0 +1,221 @@
+# include "dvo1.h"
+void copy_region (GSCRegion *in, GSCRegion *out);
+
+int imdata (int argc, char **argv) {
+  
+  int i, j, k, I;
+  int Nimage, N, NPTS, skip, mode, TimeSelect;
+  int n, Nregion, Ntregion, TimeFormat;
+  int *subset, Nsubset;
+  char filename[256];
+  double trange;
+  unsigned long tzero, start, stop, TimeReference;
+  Image *image;
+  Catalog catalog;
+  GSCRegion *region, *tregion;
+  Vector *vec;
+
+  start = stop = 0;
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+    fprintf (stderr, "searching in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+    if (trange > 0) {
+      start = tzero;
+      stop  = tzero + trange;
+    } else {
+      stop = tzero;
+      start  = tzero + trange;
+    }      
+  }
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: imdata (value) [-time t dt]\n");
+    return (FALSE);
+  }
+
+  /* identify selection */
+  mode = 0;
+  if (!strcasecmp (argv[1], "ra")) 
+    mode = 1;
+  if (!strcasecmp (argv[1], "dec")) 
+    mode = 2;
+  if (!strcasecmp (argv[1], "mag")) 
+    mode = 3;
+  if (!strcasecmp (argv[1], "dmag")) 
+    mode = 4;
+  if (!strcasecmp (argv[1], "Mcal")) 
+    mode = 5;
+  if (!strcasecmp (argv[1], "Mrel")) 
+    mode = 6;
+  if (!strcasecmp (argv[1], "source")) 
+    mode = 7;
+  if (!strcasecmp (argv[1], "x")) 
+    mode = 8;
+  if (!strcasecmp (argv[1], "y")) 
+    mode = 9;
+  if (!strcasecmp (argv[1], "time")) 
+    mode = 10;
+  if (mode == 0) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dR dec dD mag dmag Mrel Mcal source time\n");
+    return (FALSE);
+  }
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TimeSelect);
+  BuildChipMatch (image, Nimage);
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* for each image of interest, find the appropriate region files */
+  Nregion = 0;
+  ALLOCATE (region, GSCRegion, 1);
+  for (i = 0; i < Nsubset; i++) {
+    I = subset[i];
+    if (!FindMosaicForImage (image, Nimage, I)) continue;
+    tregion = get_regions (&image[I], &Ntregion);
+    REALLOCATE (region, GSCRegion, MAX (1, Nregion + Ntregion));
+    for (j = 0; j < Ntregion; j++) {
+      skip = FALSE;
+      for (k = 0; (k < Nregion) && !skip; k++) {
+	if (!strcmp (region[k].filename, tregion[j].filename)) skip = TRUE;
+      }
+      if (!skip) {
+	copy_region (&tregion[j], &region[Nregion]);
+	Nregion ++;
+      }
+    }
+    free (tregion);
+  }	
+  free (subset);
+  for (i = 0; i < Nregion; i++) {
+    fprintf (stderr, "try %s\n", region[i].filename);
+  } 
+  
+  /* create output vector */
+  NPTS = 1000;
+  REALLOCATE (vec[0].elements, float, NPTS);
+  vec[0].Nelements = N = 0;
+
+  /* for each region file, extract the data of interest in the right time range */
+  for (j = 0; j < Nregion; j++) {
+
+    /* get file name and open */
+    strcpy (filename, region[j].filename);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* assign vector values */
+    switch (mode) {
+    case (1):  /* ra */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].R - catalog.measure[i].dR / 360000.0;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (2):  /* dec */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].D - catalog.measure[i].dD / 360000.0;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (3):  /* mag */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].M / 1000.0;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (4):  /* dmag */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].dM / 1000.0;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (5):  /* Mcal */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].Mcal / 1000.0;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (6):  /* Mrel */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	n = catalog.measure[i].averef;
+	vec[0].elements[N] = catalog.average[n].M / 1000.0;
+	N++;
+      }
+      break;
+    case (7):  /* source */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = catalog.measure[i].source;
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    case (10):  /* time */
+      for (i = 0; i < catalog.Nmeasure; i++) {
+	if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
+	vec[0].elements[N] = TimeValue (catalog.measure[i].t, TimeReference, TimeFormat);
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 1000);
+      }
+      break;
+    }
+    if (catalog.average != 0) {
+      free (catalog.average);
+    }
+    if (catalog.measure != 0) {
+      free (catalog.measure);
+    }
+  }
+  
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+  return (TRUE);
+}
+
+
+void copy_region (GSCRegion *in, GSCRegion *out) {
+    
+  out[0].RA[0]  = in[0].RA[0];
+  out[0].RA[1]  = in[0].RA[1];
+  out[0].DEC[0] = in[0].DEC[0];
+  out[0].DEC[1] = in[0].DEC[1];
+  strcpy (out[0].filename, in[0].filename);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdense.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdense.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imdense.c	(revision 21703)
@@ -0,0 +1,76 @@
+# include "dvo1.h"
+extern double drand48();
+
+int imdense (int argc, char **argv) {
+  
+  long A, B;
+  int i, N, Nimage, status, NPTS, Ngraph;
+  double r, d, x, y, Rmin, Rmax;
+  Vector Xvec, Yvec;
+  Image *image;
+  Graphdata graphmode;
+
+  /* need options to list only images in region and only images in a time range */
+  /* also, option to list and not plot or plot and not list images */
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+  
+  A = time(NULL);
+  for (B = 0; A == time(NULL); B++);
+  srand48(B);
+
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  N = 0;
+  for (i = 0; i < Nimage; i++) {
+    /* choose a position for point within image box */
+    x = (0.1 + 0.9*drand48()) * image[i].NX;
+    y = (0.1 + 0.9*drand48()) * image[i].NY;
+    /* project this image to screen display coords */
+    status = FALSE;
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+    XY_to_RD (&r, &d, x, y, &image[i].coords);
+    while (r < Rmin) r += 360.0; 
+    while (r > Rmax) r -= 360.0; 
+    status |= fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], r, d, &graphmode.coords);
+    if ((Xvec.elements[N] >= graphmode.xmin) && 
+	(Xvec.elements[N] <= graphmode.xmax) && 
+	(Yvec.elements[N] >= graphmode.ymin) && 
+	(Yvec.elements[N] <= graphmode.ymax) && status) {
+      N++;
+      if (N > NPTS - 1) { 
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (image);
+  return (TRUE);
+
+}
+
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imextract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imextract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imextract.c	(revision 21703)
@@ -0,0 +1,186 @@
+# include "dvo1.h"
+
+enum {ZERO, RA, DEC, Xm, AIRMASS, MCAL, dMCAL, PHOTCODE, TIME, FWHM, EXPTIME, NSTAR, SKY, NCAL, FLAG};
+
+int imextract (int argc, char **argv) {
+  
+  int i, j, Nimage, mode, N, Ngraph, PhotcodeSelect;
+  int TimeSelect, RegionSelect, *subset, Nsubset, TimeFormat, FlagSelect, FlagValue;
+  double x, y, ra, dec, t, trange;
+  time_t tzero, TimeReference;
+
+  PhotCode *code;
+  Graphdata graphsky;
+  Image *image;
+  Vector *vec;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  /* check for time-based selection */
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+
+  /* check for region-based selection */
+  RegionSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    RegionSelect = TRUE;
+  }
+
+  /* check for region-based selection */
+  FlagValue = 0;
+  FlagSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-flag"))) {
+    remove_argument (N, &argc, argv);
+    FlagValue = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    FlagSelect = TRUE;
+  }
+
+  /* check for photcode-based selection */
+  code = NULL;
+  PhotcodeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode %s not found in photcode table\n", argv[N]);
+      return (FALSE);
+    }
+    if ((code[0].type != PHOT_PRI) && (code[0].type != PHOT_SEC) && (code[0].type != PHOT_DEP)) {
+      fprintf (stderr, "photcode must be primary, secondary, or dependent code\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imextract (value) [-region] [-time start range] [-photcode photcode]\n");
+    return (FALSE);
+  }
+  
+  /* identify selection */
+  mode = ZERO;
+  if (!strcasecmp (argv[1], "ra")) mode = RA;
+  if (!strcasecmp (argv[1], "dec")) mode = DEC;
+  if (!strcasecmp (argv[1], "Xm")) mode = Xm;
+  if (!strcasecmp (argv[1], "airmass")) mode = AIRMASS;
+  if (!strcasecmp (argv[1], "Mcal")) mode = MCAL;
+  if (!strcasecmp (argv[1], "dMcal")) mode = dMCAL;
+  if (!strcasecmp (argv[1], "photcode")) mode = PHOTCODE;
+  if (!strcasecmp (argv[1], "time")) mode = TIME;
+  if (!strcasecmp (argv[1], "FWHM")) mode = FWHM;
+  if (!strcasecmp (argv[1], "exptime")) mode = EXPTIME;
+  if (!strcasecmp (argv[1], "nstar")) mode = NSTAR;
+  if (!strcasecmp (argv[1], "ncal")) mode = NCAL;
+  if (!strcasecmp (argv[1], "sky")) mode = SKY;
+  if (!strcasecmp (argv[1], "flag")) mode = FLAG;
+  if (mode == ZERO) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dec airmass Mcal dMcal Xm photcode time fwhm exptime nstar ncal sky flag\n");
+    return (FALSE);
+  }
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image_subset (image, Nimage, &subset, &Nsubset, &graphsky, RegionSelect, tzero, trange, TimeSelect);
+  if ((mode == RA) || (mode == DEC)) BuildChipMatch (image, Nimage);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* create storage vector */
+  REALLOCATE (vec[0].elements, float, Nimage);
+  vec[0].Nelements = Nimage;
+  
+  N = 0;
+  /* assign vector values */
+  for (i = 0; i < Nsubset; i++) {
+    j = subset[i];
+    if (PhotcodeSelect) {
+      if (code[0].type == PHOT_DEP) {
+	if (code[0].code != image[j].source) continue;
+      } else {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (image[j].source)) continue;
+      }
+    }
+    if (FlagSelect && (FlagValue != image[j].code)) continue;
+    switch (mode) {
+    case (RA):
+      if (!FindMosaicForImage (image, Nimage, j)) continue;
+      x = 0.5*image[j].NX;
+      y = 0.5*image[j].NY;
+      XY_to_RD (&ra, &dec, x, y, &image[j].coords);
+      vec[0].elements[N] = ra;
+      break;
+    case (DEC):
+      if (!FindMosaicForImage (image, Nimage, j)) continue;
+      x = 0.5*image[j].NX;
+      y = 0.5*image[j].NY;
+      XY_to_RD (&ra, &dec, x, y, &image[j].coords);
+      vec[0].elements[N] = dec;
+      break;
+    case (Xm):
+      vec[0].elements[N] = pow(10.0, 0.01*image[j].Xm);
+      break;
+    case (AIRMASS):
+      vec[0].elements[N] = 0.001*image[j].secz;
+      break;
+    case (MCAL):
+      vec[0].elements[N] = 0.001*image[j].Mcal;
+      break;
+    case (dMCAL):
+      vec[0].elements[N] = 0.001*image[j].dMcal;
+      break;
+    case (PHOTCODE):
+      vec[0].elements[N] = image[j].source;
+      break;
+    case (TIME):
+      t = image[j].tzero + 0.5*image[j].NY * image[j].trate / 10000;
+      vec[0].elements[N] = TimeValue (t, TimeReference, TimeFormat);
+      break;
+    case (FWHM):
+      vec[0].elements[N] = image[j].fwhm_x / 25.0;
+      break;
+    case (EXPTIME):
+      vec[0].elements[N] = image[j].exptime;
+      break;
+    case (NSTAR):
+      vec[0].elements[N] = image[j].nstar;
+      break;
+    case (NCAL):
+      vec[0].elements[N] = image[j].Mxxxx;
+      break;
+    case (SKY):
+      vec[0].elements[N] = image[j].Myyyy + 0x8000;
+      break;
+    case (FLAG):
+      vec[0].elements[N] = image[j].code;
+      break;
+    }
+    N++;
+  }
+  
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, N);
+
+  free (subset);
+  free (image);
+  return (TRUE);
+  
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imlist.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imlist.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imlist.c	(revision 21703)
@@ -0,0 +1,94 @@
+# include "dvo1.h"
+
+int imlist (int argc, char **argv) {
+  
+  int i, j, N, Nimage, *subset, Nsubset, TimeSelect, RegionSelect, TimeFormat, NameSelect;
+  int PhotcodeSelect;
+  time_t tzero, TimeReference;
+  double r, d, trange, t;
+  char *name;
+  int Ngraph;
+  Image *image;
+  Graphdata graphmode;
+  PhotCode *PhotcodeValue;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+    fprintf (stderr, "plotting in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+  }
+
+  RegionSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    RegionSelect = TRUE;
+  }
+
+  PhotcodeValue = NULL;
+  PhotcodeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    PhotcodeValue = GetPhotcodebyName (argv[N]);
+    if (PhotcodeValue == NULL) {
+      fprintf (stderr, "photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  name = NULL;
+  NameSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    name = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    NameSelect = TRUE;
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: image [-time start range] [-region] [-name string]\n");
+    return (FALSE);
+  }
+  
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image_subset (image, Nimage, &subset, &Nsubset, &graphmode, RegionSelect, tzero, trange, TimeSelect);
+  BuildChipMatch (image, Nimage);
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    if (NameSelect && (strstr (image[i].name, name) == (char *) NULL)) continue;
+    if (PhotcodeSelect) {
+      if (PhotcodeValue[0].type == PHOT_DEP) {
+	if (PhotcodeValue[0].code != image[i].source) continue;
+      } else {
+	if (PhotcodeValue[0].code != GetPhotcodeEquivCodebyCode (image[i].source)) continue;
+      }
+    }
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+    t = TimeValue (image[i].tzero, TimeReference, TimeFormat);
+    XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+    fprintf (GetOutfile(), "%3d %s %8.4f %8.4f %f %5d %2d %4.2f %5.3f %5.3f\n", 
+	     i, image[i].name, r, d, t, image[i].nstar, image[i].source, 0.001*image[i].secz, 0.001*image[i].Mcal, 0.001*image[i].dMcal);
+  }
+
+  free (subset);
+  free (image);
+  return (TRUE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imphot.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imphot.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imphot.c	(revision 21703)
@@ -0,0 +1,100 @@
+# include "dvo1.h"
+
+int imphot (int argc, char **argv) {
+  
+  unsigned long int tzero;
+  double trange;
+  int N, GreyScale;
+  int i, j, Nimage, Nsubset, *subset;
+  char bufname[64];
+  float *p;
+  double fx, fy, x, y, applyMcal();
+  Image *image;
+  Buffer *buf;
+
+  GreyScale = FALSE;
+  if ((N = get_argument (argc, argv, "-g"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (bufname, argv[N]);
+    remove_argument (N, &argc, argv);
+    GreyScale = TRUE;
+  }
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: imphot tzero trange [-g buffer]\n");
+    return (FALSE);
+  }
+
+  buf = NULL;
+  if (GreyScale) {
+    if ((buf = SelectBuffer (bufname, ANYBUFFER, TRUE)) == NULL) return (FALSE);
+    buf[0].header.simple   = TRUE;
+    buf[0].header.unsign   = FALSE;
+    buf[0].header.extend   = FALSE;
+    buf[0].header.bitpix   = -32;
+    buf[0].header.Naxes    = 2;
+    buf[0].header.Naxis[0] = 100;
+    buf[0].header.Naxis[1] = 200;
+    buf[0].header.bzero    = 0;
+    buf[0].header.bscale   = 1;
+    CreateBuffer (&buf[0]);
+  }
+
+  /* load image(s) in time range given */
+  if (!str_to_time (argv[1], &tzero)) { 
+    fprintf (stderr, "syntax error\n");
+    return (FALSE);
+  }
+  if (!str_to_dtime (argv[2], &trange)) { 
+    fprintf (stderr, "syntax error\n");
+    return (FALSE);
+  }    
+  fprintf (stderr, "searching in range %ds - %ds (%f seconds)\n", (int)tzero, (int)(tzero + trange), trange);
+  
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  image_subset (image, Nimage, &subset, &Nsubset, (Graphdata *) NULL, FALSE, tzero, trange, TRUE);
+
+  if ((Nsubset > 1) && GreyScale) {
+    fprintf (stderr, "more than one image selected, making GreyScale of first only\n");
+  }
+
+  if (GreyScale && Nsubset) {
+    fx = image[subset[0]].NX / 100;
+    fy = image[subset[0]].NY / 200;
+    p = (float *) buf[0].matrix.buffer;
+    for (y = 0; y < 200; y+=1.0) {
+      for (x = 0; x < 100; x+=1.0, p++) {
+	*p = applyMcal (&image[subset[0]], (fx*x), (fy*y));
+      }
+    }
+  }
+
+  for (j = 0; j < Nsubset; j++) {
+    i = subset[j];
+    switch (image[i].order) {
+    case 0:
+      fprintf (stderr, "%s: %d - %d\n", image[i].name, image[i].order, image[i].Mcal);
+      break;
+    case 1:
+      fprintf (stderr, "%s: %d - %d, %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My);
+      break;
+    case 2:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, image[i].Mxx, image[i].Mxy, image[i].Myy);
+      break;
+    case 3:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d, %d %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, 
+	       image[i].Mxx, image[i].Mxy, image[i].Myy, image[i].Mxxx, image[i].Mxxy, image[i].Mxyy, image[i].Myyy);
+      break;
+    case 4:
+      fprintf (stderr, "%s: %d - %d, %d %d, %d %d %d, %d %d %d %d, %d %d %d %d %d\n", image[i].name, image[i].order, image[i].Mcal, image[i].Mx, image[i].My, 
+	       image[i].Mxx, image[i].Mxy, image[i].Myy, image[i].Mxxx, image[i].Mxxy, image[i].Mxyy, image[i].Myyy,
+	       image[i].Mxxxx, image[i].Mxxxy, image[i].Mxxyy, image[i].Mxyyy, image[i].Myyyy);
+      break;
+    }
+  }
+
+  free (image);
+  free (subset);
+  return (TRUE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imrough.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imrough.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imrough.c	(revision 21703)
@@ -0,0 +1,309 @@
+# include "dvo1.h"
+RegImage *load_imreg (char *DataBase, int *nimage);
+
+# define NVALUE 22
+enum {V_NONE, V_EXPTIME, V_CCDN, V_SKY, V_BIAS, V_FILTER, V_FWHM, V_AIRM, V_TIME, V_TEMP0, V_TEMP1, V_TEMP2, V_TEMP3, V_TELFOCUS, V_XPROBE, V_YPROBE, V_ZPROBE, V_RA, V_DEC, V_DETTEMP, V_ROTANGLE, V_REGTIME};
+static char valuename[NVALUE][32] = {"none", "exptime", "ccd", "sky", "bias", "filter", "fwhm", "airmass", "time", "temp0", "temp1", "temp2", "temp3", "telfocus", "xprobe", "yprobe", "zprobe", "ra", "dec", "dettemp", "rotangle", "regtime"};
+
+int imrough (int argc, char **argv) {
+ 
+  int i, N, Nimage, TimeSelect;
+  int ModeSelect, TypeSelect, CCDSelect, FilterSelect, TimeFormat;
+  int type, value, mode, CCD, NVEC;
+  char DataBase[256], *Filter;
+  double trange;
+  float *Vec;
+  unsigned long tzero, tend, TimeReference;
+  RegImage *image;
+  Vector *vec;
+
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-trange"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  type = T_UNDEF;
+  TypeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-type"))) {
+    TypeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    type = get_image_type (argv[N]);
+    if (type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  mode = M_NONE;
+  ModeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-mode"))) {
+    ModeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    mode = get_image_mode (argv[N]);
+    if (mode == M_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image mode %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+  }
+
+  CCD = 0;
+  CCDSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-ccd"))) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  Filter = NULL;
+  FilterSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-filter"))) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: imrough (value)\n");
+    fprintf (stderr, "       value options:\n");
+    for (i = 1; i < NVALUE; i++) {
+      fprintf (stderr, "%s\n", valuename[i]);
+    }
+    return (FALSE);
+  }
+ 
+  /* identify selection */
+  value = V_NONE;
+  for (i = 0; (i < NVALUE) && (value == V_NONE); i++) {
+    if (!strncasecmp (argv[1], valuename[i], strlen(argv[1]))) value = i;
+  }
+  if (value == V_NONE) {
+    fprintf (stderr, "ERROR: invalid image value %s\n", argv[1]);
+    return (FALSE);
+  }
+
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  image = load_imreg (DataBase, &Nimage);
+  if (image == (RegImage *) NULL) return (FALSE);
+
+  N = 0;
+  NVEC = 1000;
+  REALLOCATE (vec[0].elements, float, NVEC);
+  Vec = vec[0].elements;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  /* get data */
+  for (i = 0; i < Nimage; i++) {
+    /* skip unmatched selections */
+    if (TimeSelect && ((image[i].obstime < tzero) || (image[i].obstime > tzero + trange))) continue;
+    if (TimeSelect && ((image[i].obstime < tzero) || (image[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (image[i].filter, Filter))) continue;
+    if (CCDSelect && (image[i].ccd != CCD)) continue;
+    if (TypeSelect && (image[i].type != type)) continue;
+    if (ModeSelect && (image[i].mode != mode)) continue;
+
+    /* assign correct value */
+    switch (value) {
+    case (V_EXPTIME):
+      Vec[N] = image[i].exptime;
+      break;
+    case (V_CCDN):
+      Vec[N] = image[i].ccd;
+      break;
+    case (V_SKY):
+      Vec[N] = image[i].sky;
+      break;
+    case (V_BIAS):
+      Vec[N] = image[i].bias;
+      break;
+    case (V_FILTER):
+      Vec[N] = image[i].filter[0];
+      break;
+    case (V_FWHM):
+      Vec[N] = image[i].fwhm;
+      break;
+    case (V_AIRM):
+      Vec[N] = image[i].airmass;
+      break;
+    case (V_TIME):
+      Vec[N] = TimeValue (image[i].obstime, TimeReference, TimeFormat);
+      break;
+    case (V_TEMP0):
+      Vec[N] = image[i].teltemp_0;
+      break;
+    case (V_TEMP1):
+      Vec[N] = image[i].teltemp_1;
+      break;
+    case (V_TEMP2):
+      Vec[N] = image[i].teltemp_2;
+      break;
+    case (V_TEMP3):
+      Vec[N] = image[i].teltemp_3;
+      break;
+    case (V_TELFOCUS):
+      Vec[N] = image[i].telfocus;
+      break;
+    case (V_XPROBE):
+      Vec[N] = image[i].xprobe;
+      break;
+    case (V_YPROBE):
+      Vec[N] = image[i].yprobe;
+      break;
+    case (V_ZPROBE):
+      Vec[N] = image[i].zprobe;
+      break;
+    case (V_RA):
+      Vec[N] = image[i].ra;
+      break;
+    case (V_DEC):
+      Vec[N] = image[i].dec;
+      break;
+    case (V_DETTEMP):
+      Vec[N] = image[i].dettemp;
+      break;
+    case (V_ROTANGLE):
+      Vec[N] = image[i].rotangle;
+      break;
+    case (V_REGTIME):
+      Vec[N] = TimeValue (image[i].regtime, TimeReference, TimeFormat);
+      break;
+    }
+    N++;
+    if (N >= NVEC - 1) {
+      NVEC += 1000;
+      REALLOCATE (vec[0].elements, float, NVEC);
+      Vec = vec[0].elements;
+    }
+  }
+
+  REALLOCATE (vec[0].elements, float, MAX (1,N));
+  vec[0].Nelements = N;
+
+  free (image);
+  return (TRUE);
+
+}
+
+RegImage *load_imreg (char *DataBase, int *nimage) {
+
+  int Nimage, status;
+  char line[80];
+  FILE *f;
+  Header header, theader;
+  Matrix matrix;
+  FTable table;
+  RegImage *image;
+
+  *nimage = 0;
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* load in database header */
+  if (!fits_fread_header (f, &header)) {
+    fclose (f);
+    fits_free_header (&header);
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* check for database v1, v2 */
+  fits_scan (&header, "ORIGIN", "%s", 1, line);
+  if (!strcmp (line, "MDM Observatory")) {
+
+    fseek (f, header.size, SEEK_SET);
+    
+    /* load existing data from database */
+    fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+    ALLOCATE (image, RegImage, Nimage);
+    status = Fread (image, sizeof(RegImage), Nimage, f, "regimage");
+    fclose (f);
+    
+    if (status != Nimage) {
+      fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+      fits_free_header (&header);
+      free (image);
+      return ((RegImage *) NULL);
+    }
+
+    *nimage = Nimage;
+    return (image);
+  }
+
+  /* we probably have v3 */
+  if (!fits_fread_matrix (f, &matrix, &header)) {
+    fclose (f);
+    fits_free_header (&header);
+    fits_free_matrix (&matrix);
+    fprintf (stderr, "ERROR: trouble reading database matrix\n");
+    return ((RegImage *) NULL);
+  }
+
+  table.header = &theader;
+  if (!fits_fread_ftable  (f, &table, "IMAGE_DATABASE")) {
+    fclose (f);
+    fits_free_header (&header);
+    fits_free_matrix (&matrix);
+    fprintf (stderr, "ERROR: trouble reading database table\n");
+    return ((RegImage *) NULL);
+  }
+
+  /* convert to internal format */
+  image = (RegImage *) table.buffer;
+  fits_scan (table.header, "NAXIS2", "%d", 1, &Nimage);
+  ConvertStruct ((char *) image, sizeof (RegImage), Nimage, "regimage");
+
+  fits_free_header (&header);
+  fits_free_matrix (&matrix);
+
+  *nimage = Nimage;
+  return (image);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imsearch.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imsearch.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imsearch.c	(revision 21703)
@@ -0,0 +1,153 @@
+# include "dvo1.h"
+
+int imsearch (int argc, char **argv) {
+ 
+  char DataBase[256], name[64];
+  FILE *f;
+  Header header;
+  RegImage *pimage;
+  int i, Nimage, status, N, TimeSelect, SaveNames;
+  int ModeSelect, TypeSelect, CCDSelect, FilterSelect;
+  char *Filter, *obstime;
+  int Type, Mode, CCD;
+  unsigned long int tzero;
+  double trange;
+   
+  VarConfig ("REGISTRATION_DATABASE", "%s", DataBase);
+
+  SaveNames = FALSE;
+  if ((N = get_argument (argc, argv, "-save"))) {
+    remove_argument (N, &argc, argv);
+    SaveNames = TRUE;
+  }
+ 
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TimeSelect = TRUE;
+  }
+ 
+  Type = 0;
+  TypeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-type"))) {
+    remove_argument (N, &argc, argv);
+    Type = get_image_type (argv[N]);
+    if (Type == T_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image type %s\n", argv[N]);
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    TypeSelect = TRUE;
+  }
+ 
+  Mode = 0;
+  ModeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-mode"))) {
+    remove_argument (N, &argc, argv);
+    Mode = get_image_mode (argv[N]);
+    if (Mode == M_UNDEF) {
+      fprintf (stderr, "ERROR: invalid image mode %s\n", argv[N]);
+      exit (1);
+    }
+    remove_argument (N, &argc, argv);
+    ModeSelect = TRUE;
+  }
+ 
+  CCD = 0;
+  CCDSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-ccd"))) {
+    remove_argument (N, &argc, argv);
+    CCD = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+    CCDSelect = TRUE;
+  }
+ 
+  Filter = NULL;
+  FilterSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-filter"))) {
+    remove_argument (N, &argc, argv);
+    Filter = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    FilterSelect = TRUE;
+    if (!strcasecmp (Filter, "X")) {
+      FilterSelect = FALSE;
+    }
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: imsearch [-time start range] [-type type] [-mode mode] [-ccd N] [-filter name]\n");
+    exit (1);
+  }
+
+  /* load in database header */
+  if (!fits_read_header (DataBase, &header)) {
+    fprintf (stderr, "ERROR: trouble reading database header\n");
+    return (FALSE);
+  }
+
+  /* open database */
+  f = fopen (DataBase, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "ERROR: can't open Registration Database\n");
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET);
+
+  /* load existing data from database */
+  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
+  ALLOCATE (pimage, RegImage, Nimage);
+  status = Fread (pimage, sizeof(RegImage), Nimage, f, "regimage");
+  fclose (f);
+
+  if (status != Nimage) {
+    fprintf (stderr, "ERROR: header and data in dB don't match (%d vs %d)\n", Nimage, status);
+    fits_free_header (&header);
+    free (pimage);
+    return (FALSE);
+  }
+
+  /* print out all data */
+  N = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (TimeSelect && ((pimage[i].obstime < tzero) || (pimage[i].obstime > tzero + trange))) continue;
+    if (FilterSelect && (strcasecmp (pimage[i].filter, Filter))) continue;
+    if (ModeSelect && (pimage[i].mode != Mode)) continue;
+    if (CCDSelect && (pimage[i].ccd != CCD)) continue;
+    if (TypeSelect && (pimage[i].type != Type)) continue;
+
+    obstime = ctime ((time_t *)&pimage[i].obstime);
+    obstime[strlen(obstime)-1] = 0;
+
+    fprintf (stdout, "%5d %6s %6s %2d %2d   ", i, get_type_name(pimage[i].type), get_mode_name(pimage[i].mode), pimage[i].ccd, pimage[i].type);
+    fprintf (stdout, "%s %s  ", pimage[i].pathname, pimage[i].filename);
+    fprintf (stdout, "%s %s %f %s\n", pimage[i].filter, pimage[i].instrument, pimage[i].exptime, obstime);
+
+    if (SaveNames) {
+      sprintf (name, "IMAGEpath:%d", N);
+      set_str_variable (name, pimage[i].pathname);
+      sprintf (name, "IMAGEfile:%d", N);
+      set_str_variable (name, pimage[i].filename);
+      sprintf (name, "IMAGEmode:%d", N);
+      set_int_variable (name, pimage[i].mode);
+    }
+    N++;
+  }
+  if (SaveNames) {
+    set_int_variable ("IMAGEpath:n", N);
+    set_int_variable ("IMAGEfile:n", N);
+  }
+
+  free (pimage);
+  fits_free_header (&header);
+  return (TRUE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imstats.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imstats.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/imstats.c	(revision 21703)
@@ -0,0 +1,70 @@
+# include "dvo1.h"
+
+int imstats (int argc, char **argv) {
+  
+  int i, Nimage, N;
+  int Mcal, AutoLimits, Ngraph;
+  double r, d;
+  Image *image;
+  Vector Xvec, Yvec;  
+  Graphdata graphmode;
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  Mcal = TRUE;
+  if ((N = get_argument (argc, argv, "-dM"))) {
+    remove_argument (N, &argc, argv);
+    Mcal = FALSE;
+  }
+
+  AutoLimits = FALSE;
+  if ((N = get_argument (argc, argv, "-l"))) {
+    remove_argument (N, &argc, argv);
+    AutoLimits = TRUE;
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: imstats [-dM] [-l]\n");
+    return (FALSE);
+  }
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  /* assign vector values */
+  Xvec.Nelements = Nimage;
+  Yvec.Nelements = Nimage;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  fprintf (stdout, "seq  ra (J2000) dec    time (s)   Nstars\n");
+  for (i = 0; i < Nimage; i++) {
+    Xvec.elements[i] = 0.001*image[i].secz;
+    if (Mcal) 
+      Yvec.elements[i] = 0.001*image[i].Mcal;
+    else 
+      Yvec.elements[i] = 0.001*image[i].dMcal;
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+    XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
+    fprintf (stderr, "%d %8.4f %8.4f %10d %6d  %5.3f %6.3f %6.3f\n", 
+	     i, r, d, image[i].tzero, image[i].nstar, Xvec.elements[i], 
+	     0.001*image[i].Mcal, 0.001*image[i].dMcal);
+  } 
+  if (AutoLimits) SetLimits (&Xvec, &Yvec, &graphmode);
+
+  graphmode.style = 2;
+  graphmode.etype = 0;
+  PrepPlotting (Nimage, &graphmode);
+  PlotVector (Nimage, Xvec.elements);
+  PlotVector (Nimage, Yvec.elements);
+  
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/init.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/init.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/init.c	(revision 21703)
@@ -0,0 +1,113 @@
+# include "dvo1.h"
+
+int avextract	    PROTO((int, char **));
+int badimages	    PROTO((int, char **));
+int calextract	    PROTO((int, char **));
+int calmextract	    PROTO((int, char **));
+int catlog	    PROTO((int, char **));
+int ccd		    PROTO((int, char **));
+int cmatch	    PROTO((int, char **));
+int cmd		    PROTO((int, char **));
+int cmpload	    PROTO((int, char **));
+int cmpread	    PROTO((int, char **));
+int ddmags	    PROTO((int, char **));
+int detrend	    PROTO((int, char **));
+int dmagaves	    PROTO((int, char **));
+int dmagmeas	    PROTO((int, char **));
+int dmags	    PROTO((int, char **));
+int dmt		    PROTO((int, char **));
+int elixir          PROTO((int, char **));
+int fitcolors       PROTO((int, char **));
+int gcat	    PROTO((int, char **));
+int getxtra	    PROTO((int, char **));
+int gimages	    PROTO((int, char **));
+int gstar	    PROTO((int, char **));
+int gtypes	    PROTO((int, char **));
+int images	    PROTO((int, char **));
+int imbox	    PROTO((int, char **));
+int imdata	    PROTO((int, char **));
+int imdense	    PROTO((int, char **));
+int imextract	    PROTO((int, char **));
+int imlist	    PROTO((int, char **));
+int imphot	    PROTO((int, char **));
+int imrough	    PROTO((int, char **));
+int imsearch	    PROTO((int, char **));
+int imstats	    PROTO((int, char **));
+int lcat	    PROTO((int, char **));
+int lcurve	    PROTO((int, char **));
+int lightcurve	    PROTO((int, char **));
+int mextract	    PROTO((int, char **));
+int pcat	    PROTO((int, char **));
+int photcodes	    PROTO((int, char **));
+int pmeasure	    PROTO((int, char **));
+int procks	    PROTO((int, char **));
+int showtile	    PROTO((int, char **));
+int skycoverage	    PROTO((int, char **));
+int simage	    PROTO((int, char **));
+int subpix	    PROTO((int, char **));
+int version         PROTO((int, char **));
+
+/* temporarily exclude
+int addxtra	    PROTO((int, char **));
+  {"addxtra",     addxtra,      "add extra data to object"},
+  {"getxtra",     getxtra,      "get extra data from object"},
+*/
+
+static Command cmds[] = {  
+  {"avextract",   avextract,    "extract average data values"},
+  {"badimages",   badimages,    "look for images with anomalous astrometry"},
+  {"calextract",  calextract,   "extract photometry calibration"},
+  {"calmextract", calmextract,  "extract photometry calibration"},
+  {"catalog",     catlog,       "plot catalog stars"},
+  {"ccd",         ccd,          "plot color-color diagram"},
+  {"cmatch",      cmatch,       "match two catalogs"},
+  {"cmd",         cmd,          "plot cmd of stars in current region"},
+  {"cmpload",     cmpload,      "load cmp file into ?"},
+  {"cmpread",     cmpread,      "read data from cmp format files"},
+  {"ddmags",      ddmags,       "plot magnitude differences"},
+  {"detrend", 	  detrend,      "extract from detrend database?"},
+  {"dmagaves",    dmagaves,     "foo"},
+  {"dmagmeas",    dmagmeas,     "foo"},
+  {"dmags",       dmags,        "plot differential magnitudes between filters"},
+  {"dmt",         dmt,          "plot mag scatter"},
+  {"elixir",      elixir,       "talk to elixir"},
+  {"fitcolors",   fitcolors,    "fit chip-to-chip color terms"},
+  {"gcat",    	  gcat,         "get catalog at location"},
+  {"gimages", 	  gimages,      "get images at location"},
+  {"gstar",       gstar,        "get star statistics"},
+  {"images",  	  images,       "plot image boxes"},
+  {"imbox",   	  imbox,        "plot expected image box"},
+  {"imdata",  	  imdata,       "extract data for specific images"},
+  {"imdense", 	  imdense,      "image density plot"},
+  {"imextract",   imextract,    "extract vectors from catalogs"},
+  {"imlist",      imlist,       "list image info"},
+  {"imphot",      imphot,       "image photometry info"},
+  {"imrough",     imrough,      "get info from imruf database"},
+  {"imsearch",    imsearch,     "get info from imreg database"},
+  {"imstats", 	  imstats,      "plot image statistics"},
+  {"lcat",    	  lcat,         "list catalogs in region"},
+  {"lcurve",      lcurve,       "plot lightcurve for a star"},
+  {"lightcurve",  lightcurve,   "extract lightcurve for a star"},
+  {"mextract",    mextract,     "extract measure data values"},
+  {"pcat",    	  pcat,         "plot catalog boundaries"},
+  {"photcodes",   photcodes,    "list photometry codes"},
+  {"pmeasure",    pmeasure,     "plot individual measurements"},
+  {"procks",      procks,       "plot rocks"},
+  {"showtile",    showtile,     "plot tile pattern"},
+  {"skycoverage", skycoverage,  "measure image union on sky"},
+  {"simage",      simage,       "plot stars in an image"},
+  {"subpix",      subpix,       "get subpixel positions"},
+  {"version",     version,      "show version information"},
+}; 
+
+/* move to astro */
+
+void InitDVO () {
+  
+  int i;
+
+  for (i = 0; i < sizeof (cmds) / sizeof (Command); i++) {
+    AddCommand (&cmds[i]);
+  }
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcat.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcat.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcat.c	(revision 21703)
@@ -0,0 +1,50 @@
+# include "dvo1.h"
+
+int lcat (int argc, char **argv) {
+  
+  double Radius;
+  int i, N, Nregions, ShowAll;
+  RegionFile *regions;
+  char filename[128], exists;
+  struct stat filestat;
+  char catdir[256];
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  ShowAll = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    ShowAll = TRUE;
+  }
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: lcat [-all]\n");
+    return (FALSE);
+  }
+
+  Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+  regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    exists = 'Y';
+    if (stat (filename, &filestat) == -1) exists = 'N';
+    if (ShowAll) {
+      fprintf (stderr, "%3d %s  %c\n", i, regions[i].name, exists);
+    } else {
+      if (exists == 'Y') {
+	fprintf (stderr, "%3d %s\n", i, regions[i].name);
+      }
+    }
+  }
+
+  return (TRUE);
+
+  free (regions);
+
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcurve.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcurve.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lcurve.c	(revision 21703)
@@ -0,0 +1,200 @@
+# include "dvo1.h"
+
+int lcurve (int argc, char **argv) {
+  
+  char filename[128], string[128], catdir[256], *p;
+  double Ra, Dec, Radius, Radius2, r;
+  float *RA, *DEC;
+  int Ngraph, Xgraph, TimeFormat;
+  int Nstars, found, AutoLimits, ErrorBars, GalMag, AbsPhot, SaveVectors;
+  int i, j, m, N, NPTS, *N1, Nregions;
+  time_t TimeReference;
+  struct tm *timeptr;
+  RegionFile *regions;
+  Vector *xvec, *yvec;
+  Vector Xvec, Yvec, dYvec;
+  Catalog catalog;
+  Graphdata graphmode;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  Ngraph = -1;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    Ngraph = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetGraph (&graphmode, &Xgraph, &Ngraph)) return (FALSE);
+
+  AutoLimits = FALSE;
+  if ((N = get_argument (argc, argv, "-l"))) {
+    remove_argument (N, &argc, argv);
+    AutoLimits = TRUE;
+  }
+
+  xvec = yvec = NULL;
+  SaveVectors = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    remove_argument (N, &argc, argv);
+    SaveVectors = TRUE;
+    if ((xvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+    if ((yvec = SelectVector (argv[N], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    remove_argument (N, &argc, argv);
+  }
+
+  AbsPhot = FALSE;
+  if ((N = get_argument (argc, argv, "-abs"))) {
+    remove_argument (N, &argc, argv);
+    AbsPhot = TRUE;
+  }
+
+  GalMag = FALSE;
+  if ((N = get_argument (argc, argv, "-gal"))) {
+    fprintf (stderr, "galaxy magnitudes currently disabled\n");
+    return (FALSE);
+  }
+
+  ErrorBars = FALSE;
+  if ((N = get_argument (argc, argv, "-d"))) {
+    remove_argument (N, &argc, argv);
+    ErrorBars = TRUE;
+  }
+
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: lcurve RA DEC Radius\n");
+    return (FALSE);
+  }
+  
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  Radius = atof (argv[3]);
+
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* set filename, read in header */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, float, Nstars);
+  ALLOCATE (DEC, float, Nstars);
+  ALLOCATE (N1, int, Nstars);
+
+  /* find star(s) in RA, DEC list -- use a dumb algorithm for now, improve later */
+  /* stars are not guaranteed to be sorted in RA or in DEC, so first sort the list */
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    N1[i] = i;
+  }
+  /* sort list by DEC */
+  if (Nstars > 1) sort_lists (DEC, RA, N1, Nstars);
+  /* at this point, RA, DEC, and N1 are sorted by DEC.  
+     catalog.average[N1[i]].R = RA[i] */
+
+  NPTS = 100;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  if (ErrorBars) { ALLOCATE (dYvec.elements, float, NPTS); }
+  N = 0;
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  Radius2 = Radius*Radius;
+  found = FALSE;
+  for (i = 0; (i < catalog.Naverage) && !found; i++) {
+
+    /* this can be improved by using a couple of jumps to get within range */
+    if (Dec > DEC[i] + Radius)
+      continue;
+    
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      /* found star, extract measurements */
+      m = catalog.average[N1[i]].offset;
+      for (j = 0; j < catalog.average[N1[i]].Nm; j++, m++) {
+	if (ErrorBars) dYvec.elements[N] = 0.001*catalog.measure[m].dM;
+	Xvec.elements[N] = TimeValue (catalog.measure[m].t, TimeReference, TimeFormat);
+	Yvec.elements[N] = PhotCat (&catalog.measure[m]);
+	/**** need to use PhotRel optionally here ****/
+	N++; 
+	if (N == NPTS) {
+	  NPTS += 100;
+	  REALLOCATE (Xvec.elements, float, NPTS);
+	  REALLOCATE (Yvec.elements, float, NPTS);
+	  if (ErrorBars) { REALLOCATE (dYvec.elements, float, NPTS); }
+	}
+      }      
+    }
+  }
+  Xvec.Nelements = Yvec.Nelements = N;
+  if (ErrorBars) dYvec.Nelements = N;
+  
+  if (ErrorBars)
+    sortthree (Xvec.elements, Yvec.elements, dYvec.elements, N);
+  else
+    fsortpair (Xvec.elements, Yvec.elements, N);
+
+  /* autoscale the plot */
+  if (AutoLimits) SetLimits (&Xvec, &Yvec, &graphmode);
+
+  if (ErrorBars) 
+    graphmode.etype = 1;  /* y errors only in lcurves */
+  else
+    graphmode.etype = 0;  
+
+  PrepPlotting (N, &graphmode);
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+  if (ErrorBars) {
+    PlotVector (N, dYvec.elements);
+    PlotVector (N, dYvec.elements);
+  }
+
+  timeptr = gmtime ((time_t *)&TimeReference);
+
+  if ((p = get_variable ("TIMEFORMAT")) == (char *) NULL) p = strcreate ("days");
+  sprintf (string, "%s since %02d/%02d/%02d UT", p,
+	   timeptr[0].tm_year, timeptr[0].tm_mon+1, timeptr[0].tm_mday);
+  free (p);
+  SendLabel (string, Xgraph, 0);
+
+  free (RA);
+  free (DEC);
+  free (N1);
+
+  if (SaveVectors) {
+    free (xvec[0].elements);
+    free (yvec[0].elements);
+    xvec[0].elements = Xvec.elements;
+    yvec[0].elements = Yvec.elements;
+    xvec[0].Nelements = yvec[0].Nelements = Xvec.Nelements;
+  } else {
+    free (Xvec.elements);
+    free (Yvec.elements);
+  }
+
+  if (ErrorBars) free (dYvec.elements);
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+ 
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lightcurve.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lightcurve.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/lightcurve.c	(revision 21703)
@@ -0,0 +1,150 @@
+# include "dvo1.h"
+
+int lightcurve (int argc, char **argv) {
+  
+  char filename[128], catdir[256];
+  double Ra, Dec, Radius, Radius2, r;
+  float *RA, *DEC;
+  int Nstars, found, PhotCodeSelect;
+  int i, j, k, m, N, NPTS, Nsec, RELPHOT, *N1, Nregions, TimeFormat;
+  time_t TimeReference;
+  RegionFile *regions;
+  Vector *tvec, *mvec, *dmvec;
+  Catalog catalog;
+  PhotCode *code;
+
+  VarConfig ("CATDIR", "%s", catdir);
+  if (!InitPhotcodes ()) return (FALSE);
+  Nsec = GetPhotcodeNsecfilt ();
+
+  if ((tvec = SelectVector ("tc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((mvec = SelectVector ("mc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((dmvec = SelectVector ("dmc", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  RELPHOT = FALSE;
+  if ((N = get_argument (argc, argv, "-rel"))) {
+    remove_argument (N, &argc, argv);
+    RELPHOT = TRUE;
+  }
+
+  code = NULL;
+  PhotCodeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    remove_argument (N, &argc, argv);
+    if ((code = GetPhotcodebyName (argv[N])) == NULL) {
+      fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    PhotCodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc < 4) {
+    fprintf (stderr, "USAGE: lightcurve RA DEC Radius\n");
+    return (FALSE);
+  }
+  
+  Ra = atof (argv[1]);
+  Dec = atof (argv[2]);
+  Radius = atof (argv[3]);
+
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* set filename, read in header */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, float, Nstars);
+  ALLOCATE (DEC, float, Nstars);
+  ALLOCATE (N1, int, Nstars);
+
+  /* find star(s) in RA, DEC list -- use a dumb algorithm for now, improve later */
+  /* stars are not guaranteed to be sorted in RA or in DEC, so first sort the list */
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    N1[i] = i;
+  }
+  /* sort list by DEC */
+  if (Nstars > 1) sort_lists (DEC, RA, N1, Nstars);
+  /* at this point, RA, DEC, and N1 are sorted by DEC.  
+     catalog.average[N1[i]].R = RA[i] */
+
+  N = 0;
+  NPTS = 100;
+  REALLOCATE (tvec[0].elements, float, NPTS);
+  REALLOCATE (mvec[0].elements, float, NPTS);
+  REALLOCATE (dmvec[0].elements, float, NPTS);
+  
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  Radius2 = Radius*Radius;
+  found = FALSE;
+  for (i = 0; (i < catalog.Naverage) && !found; i++) {
+
+    /* this can be improved by using a couple of jumps to get within range */
+    if (Dec > DEC[i] + Radius)
+      continue;
+    
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      k = N1[i];
+      /* found star, extract measurements */
+      m = catalog.average[k].offset;
+      for (j = 0; j < catalog.average[k].Nm; j++, m++) {
+
+	if (PhotCodeSelect) {
+	  if ((code[0].type == PHOT_REF) || (code[0].type == PHOT_DEP)) {
+	    if (code[0].code != catalog.measure[m].source) continue;
+	  } 
+	  if ((code[0].type == PHOT_PRI) || (code[0].type == PHOT_SEC)) {
+	    if (code[0].code != GetPhotcodeEquivCodebyCode (catalog.measure[m].source)) continue;
+	  } 
+	}      
+
+	tvec[0].elements[N] = TimeValue (catalog.measure[m].t, TimeReference, TimeFormat);
+	dmvec[0].elements[N] = 0.001*catalog.measure[m].dM;
+	if (RELPHOT) {
+	  mvec[0].elements[N] = PhotCat (&catalog.measure[m]);
+	} else {
+	  mvec[0].elements[N] = PhotRel (&catalog.measure[m], &catalog.average[k], &catalog.secfilt[k*Nsec]);
+	}
+	N++; 
+	if (N == NPTS) {
+	  NPTS += 100;
+	  REALLOCATE (tvec[0].elements, float, NPTS);
+	  REALLOCATE (mvec[0].elements, float, NPTS);
+	  REALLOCATE (dmvec[0].elements, float, NPTS);
+	}
+      }      
+    }
+  }
+  sortthree (tvec[0].elements, mvec[0].elements, dmvec[0].elements, N);
+  tvec[0].Nelements = mvec[0].Nelements = dmvec[0].Nelements = N;
+
+  free (RA);
+  free (DEC);
+  free (N1);
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+  if (catalog.secfilt != 0) free (catalog.secfilt);
+ 
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/match_image.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/match_image.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/match_image.c	(revision 21703)
@@ -0,0 +1,73 @@
+# include "dvo1.h"
+
+int match_image (Image *image, int Nimage, unsigned int T, short int S) {
+
+  int N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[N].tzero == T) && (image[N].source == S)) {
+      return (N);
+    }
+  }
+  return (-1);
+}
+
+int match_image_subset (Image *image, int *subset, int Nsubset, unsigned int T, short int S) {
+
+  int N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[subset[N]].tzero == T) && (image[subset[N]].source == S)) {
+      return (subset[N]);
+    }
+  }
+  return (-1);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/mextract.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/mextract.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/mextract.c	(revision 21703)
@@ -0,0 +1,116 @@
+# include "dvo1.h"
+
+int mextract (int argc, char **argv) {
+  
+  int i, j, k, m, N, N1, NPTS;
+  int param, mode, Nregions, Nsec;
+  char filename[128], catdir[256], *RegionName, *RegionList, *p;
+  double *M1;
+
+  PhotCode *code;
+  Catalog catalog;
+  RegionFile *regions;
+  Vector *vec;
+
+  /* defaults */
+  regions = NULL;
+  catalog.average = (Average *) NULL; 
+  catalog.secfilt = (SecFilt *) NULL;
+  catalog.measure = (Measure *) NULL;
+  RegionName = NULL;
+  RegionList = NULL;
+  code = NULL;
+  mode = MAG_REL;
+
+  /* load photcode information */
+  if (!InitPhotcodes ()) goto escape;
+  Nsec = GetPhotcodeNsecfilt ();
+
+  /* find CATDIR in config system */
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) goto escape;
+
+  /* interpret command-line options */
+  SetSelectionParam (0);
+  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
+  if (!SetPhotSelections (&argc, argv, 1)) goto usage;
+
+  /* interpret required command-line arguments: mextract (value) */
+  if (argc != 2) goto usage;
+  param = GetMeasureParam (argv[1]);
+  if (param == MEAS_ZERO) {
+    if (!GetPhotcodeInfo (argv[1], &code, &mode)) {
+      GetMeasureParam ("help");
+      goto escape;
+    }
+    param = MEAS_MAG;
+    for (p = argv[1]; *p != 0; p++) { 
+      if (*p == '.') *p = ':';
+    }
+  }
+  if (!TestPhotSelections (&code, &mode, MEAS_ZERO)) goto escape;
+
+  /* load region corresponding to selection above */
+  if ((regions = SelectRegions (RegionName, RegionList, &Nregions)) == NULL) goto escape;
+  if (!SetImageSelection (param)) goto escape;
+
+  /* create storage vector */
+  N = 0;
+  NPTS = 1;
+  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto escape;
+
+  for (i = 0; i < Nregions; i++) {
+    /* lock, load, unlock catalog */
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS | LOAD_SECF, FALSE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    for (j = 0; j < catalog.Naverage; j++) {
+      M1 = NULL;
+      m = catalog.average[j].offset;
+      M1 = ExtractMeasures (code, mode, &catalog.average[j], &catalog.secfilt[j*Nsec], &catalog.measure[m], &N1, param);
+      for (k = 0; k < N1; k++) {
+	vec[0].elements[N] = M1[k];
+	N++;
+	CHECK_REALLOCATE (vec[0].elements, float, NPTS, N, 2000);
+      }
+      if (M1 != NULL) free (M1);
+    }
+    if (catalog.average != NULL) free (catalog.average);
+    if (catalog.secfilt != NULL) free (catalog.secfilt);
+    if (catalog.measure != NULL) free (catalog.measure);
+    catalog.average = (Average *) NULL; 
+    catalog.secfilt = (SecFilt *) NULL;
+    catalog.measure = (Measure *) NULL;
+  }
+  vec[0].Nelements = N;
+  REALLOCATE (vec[0].elements, float, MAX(1,N));
+
+  if (regions != NULL) free (regions);
+  FreeImageSelection ();
+  return (TRUE);
+
+usage:
+  fprintf (stderr, "USAGE: mextract (value) [options]\n");
+  fprintf (stderr, "  value: measure.parameter or photcode\n");
+  return (FALSE);
+
+escape:
+  FreeImageSelection ();
+  if (regions != NULL) free (regions);
+  if (catalog.average != NULL) free (catalog.average);
+  if (catalog.secfilt != NULL) free (catalog.secfilt);
+  if (catalog.measure != NULL) free (catalog.measure);
+  if (RegionName != NULL) free (RegionName);
+  if (RegionList != NULL) free (RegionList);
+  return (FALSE);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pcat.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pcat.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pcat.c	(revision 21703)
@@ -0,0 +1,82 @@
+# include "dvo1.h"
+
+int pcat (int argc, char **argv) {
+  
+  double Radius;
+  int i, j, N, Nregions, ShowAll, NPTS, Npts;
+  RegionFile *regions;
+  char filename[128];
+  struct stat filestat;
+  Vector Xvec, Yvec;
+  Graphdata graphmode;
+  double X[4], Y[4];
+  char catdir[256];
+  int Ngraph;
+
+  VarConfig ("CATDIR", "%s", catdir);
+
+  ShowAll = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    ShowAll = TRUE;
+  }
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: pcat [-all]\n");
+    return (FALSE);
+  }
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+  
+  Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+  regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+  Npts = 0;
+   
+  for (i = 0; i < Nregions; i++) {
+    sprintf (filename, "%s/%s", catdir, regions[i].name);
+    if (ShowAll || (stat (filename, &filestat) != -1)) {
+      fprintf (stderr, "%3d %s\n", i, regions[i].name);
+      RD_to_XY (&X[0], &Y[0], regions[i].RA0, regions[i].DEC0, &graphmode.coords);
+      RD_to_XY (&X[1], &Y[1], regions[i].RA0, regions[i].DEC1, &graphmode.coords);
+      RD_to_XY (&X[2], &Y[2], regions[i].RA1, regions[i].DEC1, &graphmode.coords);
+      RD_to_XY (&X[3], &Y[3], regions[i].RA1, regions[i].DEC0, &graphmode.coords);
+      for (j = 0; j < 4; j++) {
+	Xvec.elements[Npts + j*2] = X[j];
+	Yvec.elements[Npts + j*2] = Y[j];
+	if (j > 0) {
+	  Xvec.elements[Npts+2*j - 1] = Xvec.elements[Npts+2*j];
+	  Yvec.elements[Npts+2*j - 1] = Yvec.elements[Npts+2*j];
+	}
+      }
+      Xvec.elements[Npts+7] = Xvec.elements[Npts];
+      Yvec.elements[Npts+7] = Yvec.elements[Npts];
+      Npts += 8;
+      if (Npts > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+
+  fprintf (stderr, "plotting %d catalogs\n", Npts/8);
+  Xvec.Nelements = Xvec.Nelements = Npts;
+  if (Npts > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (Npts, &graphmode);
+    PlotVector (Npts, Xvec.elements);
+    PlotVector (Npts, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (regions);
+
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photcodes.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photcodes.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photcodes.c	(revision 21703)
@@ -0,0 +1,63 @@
+# include "dvo1.h"
+
+/* list or return all photcodes equivalent to the given filter */
+int photcodes (int argc, char **argv) {
+  
+  int i, Np;
+  int *list, Nlist;
+  char name[64];
+  PhotCode *code;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: photcodes (photcode)\n");
+    return (FALSE);
+  }
+
+  /* load photcodes, convert name to code */
+  if (!InitPhotcodes ()) return (FALSE);
+
+  if (!(Np = GetPhotcodeCodebyName (argv[1]))) {
+    fprintf (stderr, "ERROR: photcode not found in photcode table\n");
+    return (FALSE);
+  }
+
+  list = GetPhotcodeEquivList (Np, &Nlist);
+  
+  for (i = 0; i < Nlist; i++) {
+    code = GetPhotcodebyCode (list[i]);
+
+    sprintf (name, "photcode:name:%d", i);
+    set_str_variable (name, code[0].name);
+
+    sprintf (name, "photcode:C:%d", i);
+    set_variable (name, 0.001*code[0].C);
+
+    sprintf (name, "photcode:K:%d", i);
+    set_variable (name, code[0].K);
+
+    sprintf (name, "photcode:X:%d", i);
+    set_variable (name, code[0].X[0]);
+
+    sprintf (name, "photcode:dX:%d", i);
+    set_variable (name, 0.001*code[0].dX);
+
+    sprintf (name, "photcode:code:%d", i);
+    set_int_variable (name, code[0].code);
+
+    sprintf (name, "photcode:filter:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].equiv));
+
+    sprintf (name, "photcode:c1:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].c1));
+
+    sprintf (name, "photcode:c2:%d", i);
+    set_str_variable (name, GetPhotcodeNamebyCode (code[0].c2));
+
+    fprintf (stderr, "%5d %s %7.4f %7.4f %7.4f\n", 
+	     code[0].code, code[0].name, 0.001*code[0].C, code[0].K, code[0].X[0]);
+  }
+  set_int_variable ("photcode:n", Nlist);
+  free (list);
+  return (TRUE);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photometry.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photometry.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/photometry.c	(revision 21703)
@@ -0,0 +1,1133 @@
+# include "dvo1.h"
+
+/* match code to measure  */
+# define TESTCODE(C,M) \
+  if (C != NULL) { \
+    switch (C[0].type) { \
+    case PHOT_DEP: \
+    case PHOT_REF: \
+      if (C[0].code != M.source) continue; \
+      break; \
+    case PHOT_PRI: \
+    case PHOT_SEC: \
+      if (C[0].code != GetPhotcodeEquivCodebyCode (M.source)) continue; \
+      break; \
+    default: \
+      break; \
+  } }
+
+/* exclusions based on measure.params  */
+# define TESTMEASURE(M) \
+  if (ApplySelections[SelectionParam]) { \
+    if (TimeSelect && (M.t < tzero)) continue; \
+    if (TimeSelect && (M.t > tend)) continue; \
+    if (ErrSelect  && (M.dM > ErrValue)) continue; \
+    if (TypeSelect && (TypeValue != GetMeasureTypeCode (&M))) continue; \
+    if (iMagSelect && (PhotInst (&M) < iMagMin)) continue; \
+    if (FlagSelect && (M.flags != FlagValue)) continue; \
+  }
+
+# define SETMAG(MOUT,MEAS,MODE) \
+  MOUT = NO_MAG; \
+  if (MODE == MAG_INST) MOUT = PhotInst (&MEAS);  \
+  if (MODE == MAG_CAT)  MOUT = PhotCat  (&MEAS); \
+  if (MODE == MAG_SYS)  MOUT = PhotSys  (&MEAS, average, secfilt); \
+  if (MODE == MAG_REL)  MOUT = PhotRel  (&MEAS, average, secfilt); \
+  if (MODE == MAG_CAL)  MOUT = PhotCal  (&MEAS, average, secfilt, measure, GetPhotcodeEquivbyCode (MEAS.source)); \
+  if (MODE == MAG_AVE)  MOUT = PhotRel  (&MEAS, average, secfilt); \
+  if (MODE == MAG_REF)  MOUT = PhotCal  (&MEAS, average, secfilt, measure, GetPhotcodeEquivbyCode (MEAS.source)); \
+  if (ApplySelections[SelectionParam]) { \
+    if (MagSelect && (MOUT > MagMax)) continue; \
+    if (MagSelect && (MOUT < MagMin)) continue; \
+  }
+
+/* selection criteria */
+/* selections based on Measure quantities */
+static int TimeSelect;
+static time_t tzero, tend;
+static int MagSelect;
+static double MagMax, MagMin;
+static int TypeSelect, TypeValue;
+static int ErrSelect, ErrValue;
+static int iMagSelect;
+static double iMagMin;
+static int FlagSelect, FlagValue;
+static int TypefracSelect, TypefracType, TypefracSign;
+static double TypefracValue;
+
+/* apply selections or not */
+static int ApplySelections[4];
+static int SelectionParam;
+
+/* applied to Average quantities */
+static int PhotcodeSelect;
+static PhotCode *PhotcodeValue;
+static int PhotcodeMode;
+
+/* selections based on Average quantities */
+static int ChiSelect;
+static float ChiLimit;
+
+/* selections based on ensemble quantities */
+static int NphotSelect, NphotSign, NphotValue;
+static int NcodeSelect, NcodeSign, NcodeValue;
+static int FWHMSelect, FWHMsign;
+static double FWHMvalue, FWHMfrac;
+
+/* time concepts */
+static time_t TimeReference;
+static int TimeFormat;
+
+int GetTimeSelection (time_t *tz, time_t *te) {
+  *tz = tzero;
+  *te = tend;
+  return (TimeSelect);
+}
+
+int GetPhotcodeInfo (char *string, PhotCode **Code, int *Mode) {
+
+  PhotCode *code;
+  int mode, status;
+  char *p, *tmpstring;
+
+  /* save local copy */
+  tmpstring = strcreate (string);
+
+  /* check for code:mode in photcode name */
+  mode = MAG_NONE;
+  p = strchr (tmpstring, ':');
+  if (p != NULL) {
+    mode = GetMagMode (p + 1);
+    if (mode == MAG_NONE) {
+      fprintf (stderr, "syntax error in magnitude mode\n");
+      free (tmpstring);
+      return (FALSE);
+    }
+    *p = 0;
+  }
+
+  /* how do we handle this elsewhere? */
+  if (!strcasecmp (tmpstring, "mag")) {
+    /* need to validate mode */
+    *Mode = mode;
+    *Code = NULL;
+    free (tmpstring);
+    return (TRUE);
+  }
+
+  code = GetPhotcodebyName (tmpstring);
+  if (code == NULL) {
+    fprintf (stderr, "photcode not found in photcode table\n");
+    free (tmpstring);
+    return (FALSE);
+  }
+
+  /* test allowable cases and/or set default values */
+  status = FALSE;
+  if (code[0].type == PHOT_DEP) {
+    if (mode == MAG_NONE) mode = MAG_REL;
+    if (mode == MAG_INST) status = TRUE;
+    if (mode == MAG_CAT)  status = TRUE;
+    if (mode == MAG_SYS)  status = TRUE;
+    if (mode == MAG_REL)  status = TRUE;
+    if (mode == MAG_CAL)  status = TRUE;
+  }  
+  if ((code[0].type == PHOT_PRI) || (code[0].type == PHOT_SEC)) {
+    if (mode == MAG_NONE) mode  = MAG_AVE;
+    if (mode == MAG_INST) status = TRUE;
+    if (mode == MAG_CAT)  status = TRUE;
+    if (mode == MAG_SYS)  status = TRUE;
+    if (mode == MAG_REL)  status = TRUE;
+    if (mode == MAG_CAL)  status = TRUE;
+    if (mode == MAG_AVE)  status = TRUE;
+    if (mode == MAG_REF)  status = TRUE;
+  }  
+  if (code[0].type == PHOT_ALT) {
+    if (mode == MAG_NONE) mode  = MAG_AVE;
+    if (mode == MAG_AVE)  status = TRUE;
+    if (mode == MAG_REF)  status = TRUE;
+  }
+
+  if (code[0].type == PHOT_REF) {
+    if (mode == MAG_NONE) mode  = MAG_CAT;
+    if (mode == MAG_CAT)  status = TRUE;
+  }
+
+  if (!status) {
+    fprintf (stderr, "mismatch in photcode and magmode\n");
+    free (tmpstring);
+    return (FALSE);
+  }
+  *Code = code;
+  *Mode = mode;
+  free (tmpstring);
+  return (TRUE);
+}
+ 
+int SetSelectionParam (int param) {
+  SelectionParam = param;
+  return (TRUE);
+}
+
+int GetSelectionParam () {
+  return (SelectionParam);
+}
+
+int GetMagMode (char *string) {
+
+  int mode;
+
+  mode = MAG_NONE;
+  if (!strcasecmp (string, "inst"))   mode = MAG_INST;
+  if (!strcasecmp (string, "cat"))    mode = MAG_CAT;
+  if (!strcasecmp (string, "sys"))    mode = MAG_SYS;
+  if (!strcasecmp (string, "rel"))    mode = MAG_REL;
+  if (!strcasecmp (string, "cal"))    mode = MAG_CAL;
+  if (!strcasecmp (string, "ave"))    mode = MAG_AVE;
+  if (!strcasecmp (string, "ref"))    mode = MAG_REF;
+  return (mode);
+}
+
+int GetMeasureParam (char *parname) {
+
+  int param;
+
+  param = MEAS_ZERO;
+  if (!strcasecmp (parname, "ra"))   	 param = MEAS_RA;
+  if (!strcasecmp (parname, "dec"))  	 param = MEAS_DEC;
+  if (!strcasecmp (parname, "mag")) 	 param = MEAS_MAG;
+  if (!strcasecmp (parname, "dmag")) 	 param = MEAS_dMAG;
+  if (!strcasecmp (parname, "airmass"))  param = MEAS_AIRMASS;
+  if (!strcasecmp (parname, "exptime"))  param = MEAS_EXPTIME;
+  if (!strcasecmp (parname, "photcode")) param = MEAS_PHOTCODE;
+  if (!strcasecmp (parname, "time"))     param = MEAS_TIME;
+  if (!strcasecmp (parname, "dR")) 	 param = MEAS_dR;
+  if (!strcasecmp (parname, "dD")) 	 param = MEAS_dD;
+  if (!strcasecmp (parname, "fwhm"))   	 param = MEAS_FWHM;
+  if (!strcasecmp (parname, "dophot")) 	 param = MEAS_DOPHOT;
+  if (!strcasecmp (parname, "FLAGS"))    param = MEAS_FLAGS;
+  if (!strcasecmp (parname, "XCCD"))   	 param = MEAS_XCCD;
+  if (!strcasecmp (parname, "YCCD"))   	 param = MEAS_YCCD;
+  if (!strcasecmp (parname, "XMOSAIC"))  param = MEAS_XMOSAIC;
+  if (!strcasecmp (parname, "YMOSAIC"))  param = MEAS_YMOSAIC;
+  if (!strcasecmp (parname, "help")) {
+    fprintf (stderr, "value may be one of the following:\n");
+    fprintf (stderr, " ra dR dec dD mag dmag Mrel Mcal photcode time fwhm dophot xccd yccd xmosaic ymosaic flags\n");
+    fprintf (stderr, "value may also be a valid photcode\n");
+    fprintf (stderr, "photcodes or 'mag' may have optional magnitude type: mag,[Minst, Mcat, Msys, Mrel, Mcal]\n");
+  }
+  return (param);
+}
+  
+int GetAverageParam (char *parname) {
+
+  int param;
+
+  param = AVE_ZERO;
+  if (!strcasecmp (parname, "ra"))    param = AVE_RA;
+  if (!strcasecmp (parname, "dec"))   param = AVE_DEC;
+  if (!strcasecmp (parname, "dmag"))  param = AVE_dMAG;
+  if (!strcasecmp (parname, "mag"))   param = AVE_MAG;
+  if (!strcasecmp (parname, "Nmeas")) param = AVE_NMEAS;
+  if (!strcasecmp (parname, "Nmiss")) param = AVE_NMISS;
+  if (!strcasecmp (parname, "Xp"))    param = AVE_Xp;
+  if (!strcasecmp (parname, "Xm"))    param = AVE_Xm;
+  if (!strcasecmp (parname, "flag"))  param = AVE_FLAG;
+  if (!strcasecmp (parname, "type"))  param = AVE_TYPE;
+  if (!strcasecmp (parname, "typefrac")) {
+    if (!TypefracType) {
+      fprintf (stderr, "typefrac needs to specify type to use\n");
+      return (param);
+    }
+    param = AVE_TYPEFRAC;
+  }
+  if (!strcasecmp (parname, "Nphot")) param = AVE_NPHOT;
+  if (!strcasecmp (parname, "Ncode")) param = AVE_NCODE;
+  if (!strcasecmp (parname, "Ncrit")) param = AVE_NCRIT;
+  return (param);
+}
+
+/* I've set some selections - if these require a photcode, check if I set one */
+int TestPhotSelections (PhotCode **code, int *mode, int param) {
+
+  int NeedPhotcode, Needcode;
+
+  /* if i've supplied a photcode (code != NULL), i'm not allowed to restrict it */
+  if (code[0] != NULL) {
+    if (PhotcodeSelect) {
+      fprintf (stderr, "photcode selection rules violated: cannot restrict photcode with a photcode\n");
+      return (FALSE);
+    } else {
+      return (TRUE);
+    }
+  }
+
+  /* for measure tests, supply MEAS_ZERO */
+
+  /* if I have an average or ensemble restriction, I must have a PRI/SEC photcode */
+  NeedPhotcode = FALSE;
+  NeedPhotcode |= ChiSelect;
+  NeedPhotcode |= NphotSelect;
+  NeedPhotcode |= ErrSelect;
+  NeedPhotcode |= TypeSelect;
+  NeedPhotcode |= TypefracSelect;
+  
+  NeedPhotcode |= (param == AVE_Xm);
+  NeedPhotcode |= (param == AVE_MAG);
+  NeedPhotcode |= (param == AVE_dMAG);
+  NeedPhotcode |= (param == AVE_TYPE);
+  NeedPhotcode |= (param == AVE_NPHOT);
+  Needcode = (param == AVE_NCODE);
+
+  if (NeedPhotcode || Needcode || NcodeSelect || PhotcodeSelect) {
+    if (!PhotcodeSelect) {
+      fprintf (stderr, "photcode selection problem: value requires photcode\n");
+      return (FALSE);
+    }
+    code[0] = PhotcodeValue;
+    mode[0] = PhotcodeMode;
+  }
+  if (NeedPhotcode) {
+    if (code[0][0].type == PHOT_PRI) return (TRUE);
+    if (code[0][0].type == PHOT_SEC) return (TRUE);
+    fprintf (stderr, "photcode selection problem: average value requires PRI/SEC photcode\n");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+void GetAverageParamHelp () {
+  fprintf (stderr, "value may be one of the following:\n");
+  fprintf (stderr, " ra dec dmag Nmeas Nmiss Xm Xp Nphot Ncode flag type typefrac\n\n");
+  fprintf (stderr, "value may also be a valid photcode\n");
+  fprintf (stderr, "photcodes or 'mag' may have optional magnitude mode: mag,[Mave, Mref]\n");
+  return;
+}
+
+/* (re)load photcodes from photcode table */
+int InitPhotcodes () {
+
+  double ZERO_POINT;
+  char PhotCodeFile[256];
+
+  if (VarConfig ("ZERO_PT", "%lf", &ZERO_POINT) == (char *) NULL) return (FALSE);
+  SetZeroPoint (ZERO_POINT);
+
+  if (VarConfig ("PHOTCODE_FILE", "%s", PhotCodeFile) == (char *) NULL) return (FALSE);
+  if (!LoadPhotcodes (PhotCodeFile)) {
+    fprintf (stderr, "error loading photcodes\n");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+/* remove standard photometry filtering options, set selections */
+/* not all functions respect all selections... */
+int SetPhotSelections (int *argc, char **argv, int Nparams) {
+
+  int i, N;
+  double trange;
+
+  if ((N = get_argument (*argc, argv, "-phothelp"))) {
+    fprintf (stderr, "optional photometry selection criteria:\n");
+    fprintf (stderr, " -magrange min max\n");
+    fprintf (stderr, " -imaglim min\n");
+    fprintf (stderr, " -flag value\n");
+    fprintf (stderr, " -chisq value\n");
+    fprintf (stderr, " -photcode code\n");
+    fprintf (stderr, " -time start range\n");
+    fprintf (stderr, " -errorlim value\n");
+    fprintf (stderr, " -type type\n");
+    fprintf (stderr, " -nmeas [+/-]N\n");
+    fprintf (stderr, " -fwhm [+/-]fraction\n");
+    return (FALSE);
+  }
+
+  /* select based on measured mag (MEASURE ONLY) */
+  MagSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-magrange"))) {
+    MagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    MagMin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    MagMax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select based on instrument mag (MEASURE ONLY) */
+  iMagSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-imaglim"))) {
+    iMagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    iMagMin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of flag (MEASURE ONLY) */
+  FlagSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-flag"))) {
+    FlagSelect = TRUE;
+    remove_argument (N, argc, argv);
+    FlagValue = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of Chisq (AVERAGE ONLY) */
+  for (i = 0; i < 4; i++) ApplySelections[i] = TRUE;
+  if ((N = get_argument (*argc, argv, "-apply"))) {
+    remove_argument (N, argc, argv);
+    if (strlen(argv[N]) != Nparams) {
+      fprintf (stderr, "-apply selection must define all parameter choices\n");
+      return (FALSE);
+    }
+    for (i = 0; i < Nparams; i++) {
+      if (toupper(argv[N][i]) == 'Y') {
+	ApplySelections[i] = TRUE;
+      } else {
+	ApplySelections[i] = FALSE;
+      }
+    }
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on value of photcode */
+  PhotcodeSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-photcode"))) {
+    PhotcodeSelect = TRUE;
+    remove_argument (N, argc, argv);
+    GetPhotcodeInfo (argv[N], &PhotcodeValue, &PhotcodeMode);
+    if (PhotcodeValue == NULL) {
+      fprintf (stderr, "photcode not found in photcode table\n");
+      return (FALSE);;
+    }
+    remove_argument (N, argc, argv);
+  }
+
+  /* selection on basis of time range (MEASURE only) */
+  TimeSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-time"))) {
+    remove_argument (N, argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, argc, argv);
+    TimeSelect = TRUE;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tend = tzero;
+      tzero -= trange;
+    } else {
+      tend = tzero + trange;
+    }
+  }
+
+  /* select by error (on measure or average) */
+  ErrSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-errorlim"))) {
+    remove_argument (N, argc, argv);
+    ErrValue = 1000*atof (argv[N]);
+    remove_argument (N, argc, argv);
+    ErrSelect = TRUE;
+  }
+
+  /* select on value of Chisq (AVERAGE ONLY) */
+  ChiSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-chisq"))) {
+    ChiSelect = TRUE;
+    remove_argument (N, argc, argv);
+    ChiLimit = atof (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on measurement type: 1,2,3 (AVERAGE ONLY) */
+  TypeSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-type"))) {
+    remove_argument (N, argc, argv);
+    TypeValue = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+    TypeSelect = TRUE;
+  }
+
+  /* select on measurement type: 1,2,3 (AVERAGE ONLY) */
+  TypefracType = 0;
+  if ((N = get_argument (*argc, argv, "-usetype"))) {
+    remove_argument (N, argc, argv);
+    TypefracType = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /* select on measurement type: 1,2,3 (AVERAGE ONLY) */
+  TypefracSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-typefrac"))) {
+    remove_argument (N, argc, argv);
+    TypefracType  = atoi (argv[N]);
+    remove_argument (N, argc, argv);
+    TypefracValue = fabs (atof (argv[N]));
+    TypefracSign = 0;
+    if (argv[N][0] == '-') TypefracSign = -1;
+    if (argv[N][0] == '+') TypefracSign = +1;
+    remove_argument (N, argc, argv);
+    TypefracSelect = TRUE;
+  }
+
+  /* select by number of measurements (AVERAGE ONLY) */
+  NphotSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-nphot"))) {
+    remove_argument (N, argc, argv);
+    NphotValue = abs (atoi (argv[N]));
+    NphotSign = 0;
+    if (argv[N][0] == '-') NphotSign = -1;
+    if (argv[N][0] == '+') NphotSign = +1;
+    remove_argument (N, argc, argv);
+    NphotSelect = TRUE;
+  }
+
+  /* select by number of measurements (AVERAGE ONLY) */
+  NcodeSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-ncode"))) {
+    remove_argument (N, argc, argv);
+    NcodeValue = abs (atoi (argv[N]));
+    NcodeSign = 0;
+    if (argv[N][0] == '-') NcodeSign = -1;
+    if (argv[N][0] == '+') NcodeSign = +1;
+    remove_argument (N, argc, argv);
+    NcodeSelect = TRUE;
+  }
+
+  /* -fwhm value frac (AVERAGE ONLY) */
+  FWHMSelect = FALSE;
+  if ((N = get_argument (*argc, argv, "-fwhm"))) {
+    remove_argument (N, argc, argv);
+    FWHMvalue = abs (atof (argv[N]));
+    FWHMsign = 0;
+    if (argv[N][0] == '-') FWHMsign = -1;
+    if (argv[N][0] == '+') FWHMsign = +1;
+    remove_argument (N, argc, argv);
+    FWHMSelect = TRUE;
+    remove_argument (N, argc, argv);
+    FWHMfrac = atof (argv[N]);
+  }
+
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  return (TRUE);
+}
+
+/* extract a list of measure parameters from the specified average entry based on the pre-set selections */
+double *ExtractMeasures (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int i, Nlist, NLIST;
+  double M, *list;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+
+  /* check selections based on averages & ensembles: chisq, Nphot, etc */
+  if (!TestAverage (code, average, secfilt, measure)) return (list); 
+
+  /* look for measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    TESTCODE (code, measure[i]);  /* skip measurements not matching photcode */
+    TESTMEASURE (measure[i]);     /* exclusions based on measure.params  */
+    SETMAG (M, measure[i], mode); /* set appropriate magnitude (also does MagSelect) */ 
+
+    /* assign value */
+    list[Nlist] = GetMeasure (param, &average[0], &measure[i], M);
+    Nlist ++;
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
+/* return average.param based on the selection */
+double ExtractAverages (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int param) {
+
+  int i;
+  double value;
+
+  value = NO_MAG;
+
+  /* this function requires code set for certain value of param.  
+     use TestPhotSelectionsAverage to validate code/param choices */
+
+  /* filter by average quantities (eg, chisq, Nphot, etc) */
+  if (!TestAverage (code, average, secfilt, measure)) return (NO_MAG);
+
+  /* assign vector values */
+  switch (param) {
+    case AVE_RA:
+      value = average[0].R;
+      break;
+    case AVE_DEC:
+      value = average[0].D;
+      break;
+    case AVE_NMEAS:
+      value = average[0].Nm;
+      break;
+    case AVE_NMISS:
+      value = average[0].Nn;
+      break;
+    case AVE_Xp:
+      value = 0.01*average[0].Xp;
+      break;
+    case AVE_FLAG:
+      value = average[0].code;
+      break;
+    case AVE_MAG:
+      switch (mode) {
+	case MAG_AVE:
+	  value = PhotAve  (code, average, secfilt);
+	  break;
+	case MAG_REF:
+	  value = PhotRef  (code, average, secfilt, measure);
+	  break;
+      }
+      break;
+    case AVE_dMAG:
+      value = PhotdM (code, average, secfilt);
+      break;
+    case AVE_Xm:
+      value = PhotXm (code, average, secfilt);
+      break;
+    case AVE_TYPE:
+      value = DetermineTypeCode (average, measure, code[0].code);
+      break;
+    case AVE_TYPEFRAC:
+      value = DetermineTypefrac (average, measure, code);
+      break;
+    case AVE_NCODE:
+      value = 0;
+      for (i = 0; i < average[0].Nm; i++) {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source)) continue;
+	value ++;
+      }
+      break;
+    case AVE_NPHOT:
+      value = 0;
+      for (i = 0; i < average[0].Nm; i++) {
+	if (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source)) continue;
+	if (measure[i].flags & (ID_MEAS_POOR | ID_MEAS_SKIP)) continue;
+	value ++;
+      }
+      break;
+    case AVE_NCRIT:
+      value = 0;
+      for (i = 0; i < average[0].Nm; i++) {
+	if ((code != NULL) && (code[0].code != GetPhotcodeEquivCodebyCode (measure[i].source))) continue;
+	if (ErrSelect && (measure[i].dM > ErrValue)) continue;
+	if (FlagSelect && (measure[i].flags != FlagValue)) continue;
+	if (TypeSelect && (TypeValue != GetMeasureTypeCode (&measure[i]))) continue;
+	if (iMagSelect && (PhotInst (&measure[i]) < iMagMin)) continue;
+	value ++;
+      }
+      break;
+  }
+  return (value);
+}  
+
+/* return fraction of measures (matching code) which have requested type */
+double DetermineTypefrac (Average *average, Measure *measure, PhotCode *code) {
+
+  double frac;
+  int k, Nc, Nt;
+  
+  Nt = Nc = 0;
+  for (k = 0; k < average[0].Nm; k++) {
+    if ((code != NULL) && (code[0].code != GetPhotcodeEquivCodebyCode (measure[k].source))) continue;
+    Nc ++;
+    if (measure[k].dophot != TypefracType) continue;
+    Nt ++;
+  }
+  frac = (double) Nt / (double) Nc;
+  return (frac);
+}
+
+/* determine the representative dophot type for this photcode (must be PRI/SEC) */
+int DetermineTypeCode (Average *average, Measure *measure, int code) {
+
+  int k, N, Nt[3];
+  
+  Nt[0] = Nt[1] = Nt[2] = 0;
+  for (k = 0; k < average[0].Nm; k++) {
+    if (code != GetPhotcodeEquivCodebyCode (measure[k].source)) continue;
+    N = GetMeasureTypeCode (&measure[k]);
+    Nt[N] ++;
+  }
+  if (Nt[0]) return (0);
+  if (Nt[1]) return (1);
+  if (Nt[2]) return (2);
+  return (3);
+}
+
+int GetMeasureTypeCode (Measure *measure) {
+  switch (measure[0].dophot) {
+    case 0:
+    case 1:
+    case 2:
+      return (0);
+      break;
+    case 3:
+    case 4:
+    case 5:
+    case 7:
+    case 9:
+      return (1);
+      break;
+    case 10:
+    default:
+      return (2);
+  }
+  return (2);
+}  
+
+int Quality (Measure *measure, int IsDophot) {
+
+  return (TRUE);
+  
+  if (IsDophot) {
+    
+    if (measure[0].dophot == 4) return (FALSE);
+    return (TRUE);
+  
+  } else {
+    
+    if (0.01 * measure[0].FWx < 3.0) return (FALSE);
+    if (0.01 * measure[0].FWx > 10.0) return (FALSE);
+
+    return (TRUE);
+
+  }
+}
+
+/* test if this average object meets the specified selection criteria.
+   for photcode-dependent quantities, only test for PRI/SEC photcodes */
+int TestAverage (PhotCode *code, Average *average, SecFilt *secfilt, Measure *measure) {
+
+  int i, Nm, Type, Select;
+  double fwhm, typefrac, dM, Xm;
+
+  /** temporary special case for Jen Katz: exclude REF with Ncode > 1 */
+  if ((code != NULL) && (code[0].type == PHOT_REF)) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      TESTCODE (code, measure[i]);
+      Nm++;
+    }
+    if (Nm > 1) return (FALSE);
+  }
+
+  if (!ApplySelections[SelectionParam]) return (TRUE);
+
+  /* pass objects with more than FWHMfrac points with FWHM above / below FWHMvalue */ 
+  if (FWHMSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      fwhm = measure[i].FWx / 100.0;
+      switch (FWHMsign) {
+	case 0:
+	  if (fwhm == FWHMvalue) break;
+	  continue;
+	case +1:
+	  if (fwhm >= FWHMvalue) break;
+	  continue;
+	case -1:
+	  if (fwhm <= FWHMvalue) break;
+	  continue;
+      }
+      Nm++;
+    }
+    if (average[0].Nm * FWHMfrac > Nm) return (FALSE);
+  }
+
+  /* all selections below require a valid photcode */
+  Select = ChiSelect || ErrSelect || NcodeSelect || NphotSelect || TypeSelect || TypefracSelect;
+  if (!Select) return (TRUE);
+
+  /* must have a valid code of some kind */
+  if (code == NULL) return (FALSE);
+
+  /* for NcodeSelect, count Nmeas for appropriate photcode */
+  if (NcodeSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      TESTCODE (code, measure[i]);
+      Nm++;
+    }
+    switch (NcodeSign) {
+      case 0:
+	if (Nm == NcodeValue) break;
+	return (FALSE);
+      case 1:
+	if (Nm >= NcodeValue) break;
+	return (FALSE);
+      case -1:
+	if (Nm <= NcodeValue) break;
+	return (FALSE);
+      default:
+	return (FALSE);
+    }
+  }
+
+  /* only PRI/SEC photcodes apply the filter */
+  if (code[0].type == PHOT_DEP) return (TRUE);
+  if (code[0].type == PHOT_REF) return (TRUE);
+
+  /* exclusions based on average.params  */
+  if (ChiSelect) {
+    Xm = PhotXm (code, average, secfilt);
+    if (Xm == -1) return (FALSE);
+    if (Xm > ChiLimit) return (FALSE);
+  }
+  
+  /* for ErrSelect, check average errors */
+  if (ErrSelect) {
+    dM = iPhotdM (code, average, secfilt);
+    if (dM > ErrValue) return (NO_MAG);
+  }
+  
+  /* for NphotSelect, count Nmeas for appropriate photcode */
+  if (NphotSelect) {
+    Nm = 0;
+    for (i = 0; i < average[0].Nm; i++) {
+      TESTCODE (code, measure[i]);
+      if (measure[i].flags && ID_MEAS_SKIP) continue;
+      Nm++;
+    }
+    switch (NphotSign) {
+      case 0:
+	if (Nm == NphotValue) break;
+	return (FALSE);
+      case 1:
+	if (Nm >= NphotValue) break;
+	return (FALSE);
+      case -1:
+	if (Nm <= NphotValue) break;
+	return (FALSE);
+      default:
+	return (FALSE);
+    }
+  }
+
+  /* for TypeSelect, check on TypeCode for this object */
+  if (TypeSelect) {
+    Type = DetermineTypeCode (average, measure, code[0].code);
+    if (Type != TypeValue) return (FALSE);
+  }
+
+  /* for TypeSelect, check on TypeCode for this object */
+  if (TypefracSelect) {
+    typefrac = DetermineTypefrac (average, measure, code);
+    switch (TypefracSign) {
+      case 0:
+	if (typefrac == TypefracValue) break;
+	return (FALSE);	
+      case +1:
+	if (typefrac >= TypefracValue) break;
+	return (FALSE);	
+      case -1:
+	if (typefrac <= TypefracValue) break;
+	return (FALSE);	
+      default:
+	return (FALSE);
+    }
+  }
+
+  return (TRUE);
+}
+
+/* for this function, we don't need to call PhotRel, etc, but we
+   do need to multiply by 0.001:
+   average[].M is stored as 1000*mag where mag is PhotAbs
+   measure[].M for PHOT_REL is the same 
+*/ 
+
+/* send in:
+   Nphot - photcode number
+   Tphot - photcode type
+   Ns    - secfilt entry (-1 for PRI)
+   &catalog.average[i], 
+   &catalog.measure[catalog.average[i].offset], 
+   &catalog.secfilt[i*Nsec] 
+*/
+
+
+double *ExtractMagnitudes (PhotCode *code, int mode, Average *average, SecFilt *secfilt, Measure *measure, int *n) {
+  
+  double *M, mag;
+  int N;
+
+  if ((mode == MAG_AVE) || (mode == MAG_REF)) {
+    ALLOCATE (M, double, 1);
+    mag = ExtractAverages (code, mode, average, secfilt, measure, AVE_MAG);
+    if (mag == NO_MAG) {
+      N = 0;
+    } else {
+      N = 1;
+      M[0] = mag;
+    }
+  } else {
+    M = ExtractMeasures (code, mode, average, secfilt, measure, &N, MEAS_MAG);
+  }
+  
+  *n = N;
+  return (M);
+}
+
+/* extract delta-mag pairs applying specified selections */
+double *ExtractDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist) {
+
+  int i, j, A1, A2, N1, N2, Np, Nlist, NLIST;
+  double *M1, *M2, *list, NoMag;
+
+  /* check for special case of measure-measure - this is needed to drop self-matches */
+  A1 = ((mode[0] == MAG_AVE) || (mode[0] == MAG_REF));
+  A2 = ((mode[1] == MAG_AVE) || (mode[1] == MAG_REF));
+  if (!A1 && !A2) {
+    list = ExtractMeasuresDMag (code, mode, average, secfilt, measure, nlist);
+    return (list);
+  }
+
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+  M1 = M2 = NULL;
+  NoMag = NO_MAG * 0.001;
+
+  /* one of the two is an average, must do independently */
+  M1 = ExtractMagnitudes (code[0], mode[0], average, secfilt, measure, &N1);
+  if (N1 == 0) goto skip;
+  
+  Np = GetSelectionParam ();
+  SetSelectionParam (Np + 1);
+  M2 = ExtractMagnitudes (code[1], mode[1], average, secfilt, measure, &N2);
+  if (N2 == 0) goto skip;
+
+  /* magnitudes may be NO_MAG : set delta to NO_MAG */
+  for (i = 0; i < N1; i++) {
+    for (j = 0; j < N2; j++) {
+      if ((M1[i] == NoMag) || (M2[j] == NoMag)) {
+	list[Nlist] = NoMag;
+      } else {
+	list[Nlist] = M1[i] - M2[j];
+      }
+      Nlist ++;
+    }
+  }
+
+ skip: 
+  if (M1 != NULL) free (M1);
+  if (M2 != NULL) free (M2);
+  *nlist = Nlist;
+  return (list);
+}
+  
+/* extract a list of delta-measure-mags from the specified average entry based on the 
+   pre-set selections - does not return self-matched measurements */
+double *ExtractMeasuresDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist) {
+
+  int i, j, Np0, Np1, Nlist, NLIST;
+  double *list, M1, M2, NoMag;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+  NoMag = NO_MAG * 0.001;
+
+  /* must have two code values - drop this test? this is programming case, not a user case */
+  if (code == NULL) return (list);
+  if (code[0] == NULL) return (list);
+  if (code[1] == NULL) return (list);
+
+  /* exclude based on average parameters for both codes  */
+  if (!TestAverage (code[0], average, secfilt, measure)) return (list);
+  if (!TestAverage (code[1], average, secfilt, measure)) return (list);
+
+  Np0 = GetSelectionParam ();
+  Np1 = Np0 + 1;
+
+  /* loop twice over all measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    SetSelectionParam (Np0);
+    TESTCODE (code[0], measure[i]);
+    TESTMEASURE (measure[i]);
+    SETMAG(M1, measure[i], mode[0]);
+    for (j = 0; j < average[0].Nm; j++) {
+      if (i == j) continue;
+      SetSelectionParam (Np1);
+      TESTCODE (code[1], measure[j]);
+      TESTMEASURE (measure[j]);
+      SETMAG(M2, measure[j], mode[1]);
+      if ((M1 == NoMag) || (M2 == NoMag)) {
+	list[Nlist] = NoMag;
+      } else {
+	list[Nlist] = M1 - M2;
+      }
+      Nlist ++;
+    }
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
+/* extract a measurement list matching the number of dmag entries */
+double *ExtractByDMag (PhotCode **code, int *mode, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int A1, A2, N1;
+  double *list;
+
+  /* check for special case of measure-measure */
+  A1 = ((mode[0] == MAG_AVE) || (mode[0] == MAG_REF));
+  A2 = ((mode[1] == MAG_AVE) || (mode[1] == MAG_REF));
+  if (!A1 && !A2) {
+    list = ExtractMeasuresByDMag (code, mode, 1, average, secfilt, measure, nlist, param);
+    return (list);
+  }
+
+  /* one of the two entries results in a single element. extract the other */
+  if (A1) {
+    list = ExtractMeasures (code[1], mode[1], average, secfilt, measure, &N1, param);
+  } else {
+    list = ExtractMeasures (code[0], mode[0], average, secfilt, measure, &N1, param);
+  }
+  *nlist = N1;
+  return (list);
+}
+  
+/* extract a list of delta-measure-mags from the specified average entry based on the pre-set selections */
+double *ExtractMeasuresByDMag (PhotCode **code, int *mode, int use_first, Average *average, SecFilt *secfilt, Measure *measure, int *nlist, int param) {
+
+  int i, j, n, Nlist, NLIST;
+  double *list, M1, M2;
+  
+  *nlist = 0; 
+  Nlist = 0;
+  NLIST = MAX (1, average[0].Nm*average[0].Nm);
+  ALLOCATE (list, double, NLIST);
+
+  /* must have two code values */
+  if (code == NULL) return (list);
+  if (code[0] == NULL) return (list);
+  if (code[1] == NULL) return (list);
+
+  /* chisq, fwhm, Nphot, Ncode */
+  if (!TestAverage (code[0], average, secfilt, measure)) return (list);
+  if (!TestAverage (code[1], average, secfilt, measure)) return (list);
+
+  /* loop twice over all measures */
+  for (i = 0; i < average[0].Nm; i++) {
+    TESTCODE (code[0], measure[i]);
+    TESTMEASURE (measure[i]);
+    SETMAG(M1, measure[i], mode[0]);
+    for (j = 0; j < average[0].Nm; j++) {
+      if (i == j) continue;
+      TESTCODE (code[1], measure[j]);
+      TESTMEASURE (measure[j]);
+      SETMAG(M2, measure[j], mode[1]);
+      n = (use_first) ? i : j;
+
+      /* assign value */
+      list[Nlist] = GetMeasure (param, &average[0], &measure[n], (use_first ? M1 : M2));
+      Nlist ++;
+    }
+  }
+  *nlist = Nlist;
+  return (list);
+}
+
+double GetMeasure (int param, Average *average, Measure *measure, double mag) {
+
+  double ra, dec, x, y;
+  double value;
+  Image *image;
+  Coords *mosaic;
+
+  value = 0;
+  switch (param) {
+    case MEAS_MAG: /* magnitudes are already determined above */
+      value = mag;
+      break;
+    case MEAS_RA: /* OK */
+      value = average[0].R - measure[0].dR / 360000.0;
+      break;
+    case MEAS_DEC: /* OK */
+      value = average[0].D - measure[0].dD / 360000.0;
+      break;
+    case MEAS_dMAG: /* OK */
+      value = 0.001*measure[0].dM;
+      break;
+    case MEAS_AIRMASS: /* OK */
+      value = 0.001*measure[0].airmass;
+      break;
+    case MEAS_EXPTIME: /* OK */
+      value = pow (10.0, measure[0].dt * 0.0004);
+      break;
+    case MEAS_PHOTCODE: /* OK */
+      value = measure[0].source;
+      break;
+    case MEAS_TIME: /* OK */
+      value = TimeValue (measure[0].t, TimeReference, TimeFormat);
+      break;
+    case MEAS_dR: /* OK */
+      value = 0.01*measure[0].dR;
+      break;
+    case MEAS_dD: /* OK */
+      value = 0.01*measure[0].dD;
+      break;
+    case MEAS_FWHM: /* OK */
+      value = 0.01*measure[0].FWx;
+      break;
+    case MEAS_DOPHOT: /* OK */
+      value = measure[0].dophot;
+      break;
+    case MEAS_FLAGS: /* ? */
+      value = measure[0].flags;
+      break;
+    case MEAS_XCCD: /* OK */
+      ra  = average[0].R - measure[0].dR / 360000.0;
+      dec = average[0].D - measure[0].dD / 360000.0;
+      image = MatchImage (measure[0].t, measure[0].source);
+      if (image == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, &image[0].coords);
+      value = x;
+      break;
+    case MEAS_YCCD: /* OK */
+      ra  = average[0].R - measure[0].dR / 360000.0;
+      dec = average[0].D - measure[0].dD / 360000.0;
+      image = MatchImage (measure[0].t, measure[0].source);
+      if (image == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, &image[0].coords);
+      value = y;
+      break;
+    case MEAS_XMOSAIC: /* OK */
+      ra  = average[0].R - measure[0].dR / 360000.0;
+      dec = average[0].D - measure[0].dD / 360000.0;
+      mosaic = MatchMosaic (measure[0].t, measure[0].source);
+      if (mosaic == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, mosaic);
+      value = x;
+      break;
+    case MEAS_YMOSAIC: /* OK */
+      ra  = average[0].R - measure[0].dR / 360000.0;
+      dec = average[0].D - measure[0].dD / 360000.0;
+      mosaic = MatchMosaic (measure[0].t, measure[0].source);
+      if (mosaic == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, mosaic);
+      value = y;
+      break;
+  }
+  return (value);
+}
+
+/** the mosaic entries do not use the registered mosaic found 
+    by MatchImage (via FindMosaicForImage).  Rather, they use
+    a coordinate frame saved by SetImageSelection 
+**/
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pmeasure.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pmeasure.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/pmeasure.c	(revision 21703)
@@ -0,0 +1,161 @@
+# include "dvo1.h"
+
+int pmeasure (int argc, char **argv) {
+  
+  FILE *f;
+  int i, j, k, m, N;
+  int InRegion, Nregions, Ngraph;
+  char filename[128], catdir[256];
+  double Mz, Mr, mag;
+  double Radius, Rmin, Rmax;
+  unsigned IDclip, IDchoice, LimExclude;
+  unsigned FlagChoice, FlagClip, flags;
+  int PhotcodeClip;
+
+  Catalog catalog;
+  RegionFile *regions;
+  Graphdata graphmode;
+  Vector Xvec, Yvec, Zvec;
+
+  Ngraph = -1;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+  if (VarConfig ("CATDIR", "%s", catdir) == NULL) return (FALSE);
+  if (!InitPhotcodes ()) return (FALSE);
+
+  regions = (RegionFile *) NULL;
+  f = (FILE *) NULL;
+  Mz = 17.0;
+  Mr = -5.0;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  PhotcodeClip = -1;
+  if ((N = get_argument (argc, argv, "-p"))) {
+    remove_argument (N, &argc, argv);
+    PhotcodeClip = GetPhotcodeCodebyName (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  IDchoice = 0;
+  IDclip = FALSE;
+  if ((N = get_argument (argc, argv, "-ID"))) {
+    remove_argument (N, &argc, argv);
+    IDchoice  = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+    IDclip = TRUE;
+  }
+  FlagChoice = 0;
+  FlagClip = FALSE;
+  if ((N = get_argument (argc, argv, "-flag"))) {
+    remove_argument (N, &argc, argv);
+    FlagChoice  = atoi(argv[N]);
+    remove_argument (N, &argc, argv);
+    FlagClip = TRUE;
+  }
+
+  LimExclude = FALSE;
+  if ((N = get_argument (argc, argv, "-x"))) {
+    remove_argument (N, &argc, argv);
+    LimExclude = TRUE;
+  }
+
+  if ((N = get_argument (argc, argv, "-m"))) {
+    remove_argument (N, &argc, argv);
+    Mr  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Mz = atof(argv[N]);
+    Mr = Mr - Mz;
+    remove_argument (N, &argc, argv);
+  }
+
+  InRegion = FALSE;
+  if ((N = get_argument (argc, argv, "-all"))) {
+    remove_argument (N, &argc, argv);
+    InRegion = TRUE;
+  }
+
+  if ((InRegion || (argc != 2)) && (!InRegion || (argc != 1))) {
+    fprintf (stderr, "USAGE: catalog (filename / -all) [-m M M] [-n N N] [-g] [-a RA DEC MAG] \n");
+    return (FALSE);
+  }
+  
+  if (InRegion) {
+    Radius = MAX (fabs(graphmode.xmax), fabs(graphmode.ymax));
+    regions = find_regions (graphmode.coords.crval1, graphmode.coords.crval2, Radius, &Nregions);
+  } else {
+    Nregions = 1;
+  }
+  
+  for (j = 0; j < Nregions; j++) {
+    catalog.average = 0;
+    
+    if (InRegion) {
+      sprintf (filename, "%s/%s", catdir, regions[j].name);
+    } else {
+      sprintf (filename, "%s/%s", catdir, argv[1]);
+    }
+    
+    /* lock, load, unlock catalog */
+    catalog.filename = filename;
+    switch (lock_catalog (&catalog, LCK_SOFT)) {
+    case 2:
+      unlock_catalog (&catalog);
+    case 0:
+      continue;
+    }
+    if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+      unlock_catalog (&catalog);
+      continue;
+    }
+    unlock_catalog (&catalog);
+
+    /* data has been loaded, get ready to plot it */
+    Xvec.Nelements = catalog.Nmeasure;
+    Yvec.Nelements = catalog.Nmeasure;
+    Zvec.Nelements = catalog.Nmeasure;
+    ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+    ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+    ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+
+    /* project stars to screen display coords */
+    Xvec.Nelements = 0;
+    for (N = i = 0; i < catalog.Naverage; i++) {
+      if (IDclip && (catalog.average[i].code != IDchoice)) continue;
+      while (catalog.average[i].R < Rmin) catalog.average[i].R += 360.0;
+      while (catalog.average[i].R > Rmax) catalog.average[i].R -= 360.0;
+      m = catalog.average[i].offset;
+      for (k = 0; k < catalog.average[i].Nm; k++) {
+	if (FlagClip) {
+	  flags = catalog.measure[m+k].flags;
+	  if (!(flags & FlagChoice)) continue;
+	}
+	if ((PhotcodeClip != -1) && (catalog.measure[m+k].source != PhotcodeClip)) continue;
+	mag = PhotCat (&catalog.measure[m+k]);
+	Zvec.elements[N] = MIN (1.0, MAX (0.01, (mag - Mz) / Mr));
+	if (LimExclude && (Zvec.elements[N] > 0.99)) continue;
+	if (Zvec.elements[N] < 0.011) continue;
+	fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], catalog.average[i].R - 2.777e-6*catalog.measure[m+k].dR, catalog.average[i].D - 2.777e-6*catalog.measure[m+k].dD, &graphmode.coords);
+	N ++;
+      }
+    }
+    Zvec.Nelements = Yvec.Nelements = Xvec.Nelements = N;
+
+    graphmode.style = 2; /* set style to points */
+    graphmode.size = -1; /* point size determined by Zvec */
+    graphmode.etype = 0; /* no errorbars */
+    PrepPlotting (N, &graphmode);
+    
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+    PlotVector (N, Zvec.elements);
+
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+
+    if (catalog.average != 0) free (catalog.average);
+    if (catalog.measure != 0) free (catalog.measure);
+  }
+  return (TRUE);
+
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/procks.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/procks.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/procks.c	(revision 21703)
@@ -0,0 +1,160 @@
+# include "dvo1.h"
+
+typedef struct {
+  double ra[3];
+  double dec[3];
+  double X[3];
+  double Y[3];
+  unsigned int t[3];
+  double mag[3];
+} Rocks;
+static Rocks *rocks = (Rocks *) NULL;
+static int   Nrocks;
+
+int procks (int argc, char **argv) {
+  
+  FILE *f;
+  Vector Xvec, Yvec;
+  int i, j, N, NROCKS;
+  int N0, N1, SpeedClip, Reload;
+  unsigned int t0, t1;
+  double Mz, Mr, S0, S1;
+  double Rmin, Rmax;
+  Graphdata graphmode;
+  char rockcat[256];
+  int Ngraph;
+
+  Ngraph = 0;
+  VarConfig ("ROCK_CATALOG", "%s", rockcat);
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  f = (FILE *) NULL;
+  Mz = 17.0;
+  Mr = -5.0;
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+
+  if ((N = get_argument (argc, argv, "-m"))) {
+    remove_argument (N, &argc, argv);
+    Mr  = 1000*atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    Mz = 1000*atof(argv[N]);
+    Mr = Mr - Mz;
+    remove_argument (N, &argc, argv);
+  }
+
+  S0 = S1 = 0;
+  SpeedClip = FALSE;
+  if ((N = get_argument (argc, argv, "-speed"))) {
+    SpeedClip = TRUE;
+    remove_argument (N, &argc, argv);
+    S0 = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    S1 = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  Reload = FALSE;
+  if ((N = get_argument (argc, argv, "-reload"))) {
+    Reload = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: procks [-m M M] [-speed s s] \n");
+    return (FALSE);
+  }
+  
+  f = fopen (rockcat, "r");
+  if (f == (FILE *) NULL) {
+    fprintf (stderr, "can't open rock catalog\n");
+    return (TRUE);
+  }
+
+  if ((rocks == (Rocks *) NULL) || Reload) {
+    if (rocks != (Rocks *) NULL) free (rocks);
+    NROCKS = 100;
+    ALLOCATE (rocks, Rocks, NROCKS);
+    for (i = 0; fscanf (f, "%lf %lf %d%lf%lf%lf %d%lf%lf%lf %d%lf%lf%lf", 
+			&rocks[i].X[0], &rocks[i].Y[0], 
+			&rocks[i].t[0], &rocks[i].ra[0], &rocks[i].dec[0], &rocks[i].mag[0], 
+			&rocks[i].t[1], &rocks[i].ra[1], &rocks[i].dec[1], &rocks[i].mag[1], 
+			&rocks[i].t[2], &rocks[i].ra[2], &rocks[i].dec[2], &rocks[i].mag[2]
+			) != EOF; i++) {
+      if (i == NROCKS - 1) {
+	NROCKS += 100;
+	REALLOCATE (rocks, Rocks, NROCKS);
+      }
+    }
+    Nrocks = i;
+  }
+      
+  if (Nrocks == 0) {
+    free (rocks);
+    fprintf (stderr, "no rocks in datafile\n");
+    return (TRUE);
+  }
+
+  /* data has been loaded, get ready to plot it */
+  Yvec.Nelements = Xvec.Nelements = 3*Nrocks;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  
+  /* project stars to screen display coords */
+  for (N = i = 0; i < Nrocks; i++) {
+    if (SpeedClip && ((rocks[i].Y[0] < S0) || (rocks[i].Y[0] > S1))) continue;
+    for (j = 0; j < 3; j++) {
+      while (rocks[i].ra[j] < Rmin) rocks[i].ra[j] += 360.0;
+      while (rocks[i].ra[j] > Rmax) rocks[i].ra[j] -= 360.0;
+      fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[j], rocks[i].dec[j], &graphmode.coords);
+      N ++;
+    }
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  
+  graphmode.style = 2; /* set style to points */
+  graphmode.etype = 0; /* no errorbars */
+  PrepPlotting (N, &graphmode);
+  
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  /* now plot vectors between two extrema */
+  Yvec.Nelements = Xvec.Nelements = 2*Nrocks;
+  REALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  REALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  
+  /* project stars to screen display coords */
+  for (N = i = 0; i < Nrocks; i++) {
+    if (SpeedClip && ((rocks[i].Y[0] < S0) || (rocks[i].Y[0] > S1))) continue;
+    N0 = N1 = 0;
+    t0 = t1 = rocks[i].t[0];
+    for (j = 1; j < 3; j++) {
+      if (rocks[i].t[j] < t0) { N0 = j; t0 = rocks[i].t[j]; }
+      if (rocks[i].t[j] > t1) { N1 = j; t1 = rocks[i].t[j]; }
+    }
+    while (rocks[i].ra[N0] < Rmin) rocks[i].ra[N0] += 360.0;
+    while (rocks[i].ra[N0] > Rmax) rocks[i].ra[N0] -= 360.0;
+    while (rocks[i].ra[N1] < Rmin) rocks[i].ra[N1] += 360.0;
+    while (rocks[i].ra[N1] > Rmax) rocks[i].ra[N1] -= 360.0;
+    fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[N0], rocks[i].dec[N0], &graphmode.coords);
+    N ++;
+    fRD_to_XY (&Xvec.elements[N], &Yvec.elements[N], rocks[i].ra[N1], rocks[i].dec[N1], &graphmode.coords);
+    N ++;
+  }
+  Yvec.Nelements = Xvec.Nelements = N;
+  
+  graphmode.style = 2; /* set style to points */
+  graphmode.ptype = 100; /* connect pairs */
+  graphmode.etype = 0; /* no errorbars */
+  PrepPlotting (N, &graphmode);
+  
+  PlotVector (N, Xvec.elements);
+  PlotVector (N, Yvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
+  
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/region_list.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/region_list.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/region_list.c	(revision 21703)
@@ -0,0 +1,107 @@
+# include "dvo1.h"
+
+static int RegionSelect;
+
+int GetRegionSelection () {
+  return (RegionSelect);
+}
+
+int SetRegionSelection (int *argc, char **argv, char **RegionName, char **RegionList) {
+  
+  int N;
+
+  RegionSelect = FALSE;
+
+  /* check for Region selection */
+  *RegionName = NULL;
+  if ((N = get_argument (*argc, argv, "-cpt"))) {
+    remove_argument (N, argc, argv);
+    *RegionName = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+    return (TRUE);
+  }    
+  /* check for Region list */
+  *RegionList = NULL;
+  if ((N = get_argument (*argc, argv, "-cptlist"))) {
+    remove_argument (N, argc, argv);
+    *RegionList = strcreate (argv[N]);
+    remove_argument (N, argc, argv);
+    return (TRUE);
+  } 
+  if ((*RegionName == NULL) && (*RegionList == NULL)) {
+    RegionSelect = TRUE;
+    return (TRUE);
+  }
+
+  fprintf (stderr, "-cpt and -cptlist are incompatible\n");
+  free (*RegionName);
+  free (*RegionList);
+  *RegionName = NULL;
+  *RegionList = NULL;
+  return (FALSE);
+}
+
+RegionFile *SelectRegions (char *RegionName, char *RegionList, int *nregions) {
+
+  double Radius;
+  int Ngraph;
+  Graphdata graphsky;
+  RegionFile *regions;
+
+  /* determine region-file names */
+  if (RegionName != NULL) {
+    *nregions = 1;
+    ALLOCATE (regions, RegionFile, 1);
+    strcpy (regions[0].name, RegionName);
+    free (RegionName);
+    RegionName = NULL;
+    return (regions);
+  } 
+  if (RegionList != NULL) {
+    regions = region_list (RegionList, nregions);
+    free (RegionList);
+    RegionList = NULL;
+    return (regions);
+  }
+
+  Ngraph = 0;
+  if (!GetGraphData (&graphsky, NULL, &Ngraph)) {
+    fprintf (stderr, "region display not available\n");
+    return (NULL);
+  }
+
+  Radius = MAX (fabs(graphsky.xmax), fabs(graphsky.ymax));
+  regions = find_regions (graphsky.coords.crval1, graphsky.coords.crval2, Radius, nregions);
+  return (regions);
+}
+
+/* returns a list of region files names from file */
+RegionFile *region_list (char *filename, int *Nregions) {
+  
+  int NREGIONS, nregion;
+  RegionFile *regions;
+  FILE *f;
+
+  f = fopen (filename, "r");
+  if (f == NULL) {
+    fprintf (stderr, "ERROR: can't find region list file %s\n", filename);
+    *Nregions = 0;
+    return (NULL);
+  }
+  
+  NREGIONS = 50;
+  ALLOCATE (regions, RegionFile, NREGIONS);
+  nregion = 0;
+
+  while (fscanf (f, "%s", regions[nregion].name) != EOF) {
+    nregion ++;
+    if (nregion == NREGIONS) {
+      NREGIONS += 50;
+      REALLOCATE (regions, RegionFile, NREGIONS);
+    }
+  }
+
+  *Nregions = nregion;
+  return (regions);
+}
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/showtile.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/showtile.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/showtile.c	(revision 21703)
@@ -0,0 +1,99 @@
+# include "dvo1.h"
+static float dr[] = {0.0, 1.0, 1.0, 0.0};
+static float dd[] = {0.0, 0.0, 1.0, 1.0};
+
+int showtile (int argc, char **argv) {
+
+  int Nd, N, NPTS, Ngraph, status, i, InPic;
+  Graphdata graphmode;
+  Coords coords;
+  Vector Xvec, Yvec;
+  float r, d, R, D;
+  float Ro[90], Do[90];
+
+  /* show tile pattern in viewed region */
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: showtile [option]\n");
+    return (FALSE);
+  }
+  
+  N = 0;
+  NPTS = 200;
+  ALLOCATE (Xvec.elements, float, NPTS);
+  ALLOCATE (Yvec.elements, float, NPTS);
+
+  /* starting position */
+
+  /* reference for coords is this image */
+  coords.crpix1 = coords.crpix2 = 0.0;
+  coords.crval1 = coords.crval2 = 0.0;
+  coords.cdelt1 = coords.cdelt2 = 1.0;
+  coords.pc1_1  = coords.pc2_2  = 1.0;
+  coords.pc1_2  = coords.pc2_1  = 0.0;
+  coords.Npolyterms = 0;
+  strcpy (coords.ctype, "RA---TAN");
+  
+  /* fill in top-left region */
+  for (r = 0; r < 3; r += 1.0) {
+    fprintf (stderr, "r: %f\n", r);
+    for (Nd = d = 0; d < 90; Nd ++, d += 1.0) {
+      if (r == 0) {
+	coords.crval1 = r;
+	coords.crval2 = d;
+      } else {
+	coords.crval1 = Ro[Nd];
+	coords.crval2 = Do[Nd];
+      }
+      for (i = 0; i < 4; i++) {
+	fXY_to_RD (&R, &D, dr[i], dd[i], &coords);
+	status |= fRD_to_XY (&Xvec.elements[N+2*i], &Yvec.elements[N+2*i], R, D, &graphmode.coords);
+	if (i > 0) {
+	  Xvec.elements[N+2*i - 1] = Xvec.elements[N+2*i];
+	  Yvec.elements[N+2*i - 1] = Yvec.elements[N+2*i];
+	}
+	if (i == 1) {
+	  Ro[Nd] = R;
+	  Do[Nd] = D;
+	}
+      }
+      Xvec.elements[N+7] = Xvec.elements[N];
+      Yvec.elements[N+7] = Yvec.elements[N];
+
+      /* check if any corner is in plotting region */
+      InPic = FALSE;
+      for (i = 0; i < 8; i+=2) {
+	if ((Xvec.elements[N+i] >= graphmode.xmin) && 
+	    (Xvec.elements[N+i] <= graphmode.xmax) && 
+	    (Yvec.elements[N+i] >= graphmode.ymin) && 
+	    (Yvec.elements[N+i] <= graphmode.ymax))
+	  InPic = TRUE;
+      }
+      if (!InPic) continue;
+      N+=8;
+      if (N > NPTS - 1) {  /* this is OK because NPTS is made always a multiple of 8 */
+	NPTS += 200;
+	REALLOCATE (Xvec.elements, float, NPTS);
+	REALLOCATE (Yvec.elements, float, NPTS);
+      }
+    }
+  }
+  
+  Xvec.Nelements = Xvec.Nelements = N;
+  if (N > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PrepPlotting (N, &graphmode);
+    PlotVector (N, Xvec.elements);
+    PlotVector (N, Yvec.elements);
+  }
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  return (TRUE);
+
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/simage.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/simage.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/simage.c	(revision 21703)
@@ -0,0 +1,173 @@
+# include "dvo1.h"
+# define D_NSTARS 1000
+# define BYTES_STAR 31
+# define BLOCK 1000
+
+int simage (int argc, char **argv) {
+
+  char *buffer;
+  Vector Xvec, Yvec, Zvec;
+  double R, D, X, Y, M, zero, range;
+  FILE *f;
+  Header header;
+  Coords coords;
+  int i, j, Nstars, nstars, Nbytes, nbytes, Npts, N;
+  Graphdata graphmode;
+  int Ngraph;
+
+  Ngraph = 0;
+  if (!GetGraph (&graphmode, NULL, &Ngraph)) return (FALSE);
+
+  zero = 17.0;
+  range = -5.0;
+  if ((N = get_argument (argc, argv, "-m"))) {
+    remove_argument (N, &argc, argv);
+    range = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    zero  = atof(argv[N]);
+    range = range - zero;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: image (filename)\n");
+    return (FALSE);
+  }
+
+  fprintf (stderr, "not working at the moment (cmp format)\n");
+  return (FALSE);
+  
+  /* read header */
+  if (!fits_read_header (argv[1], &header)) {
+    fprintf (stderr, "ERROR: can't find image file %s\n", argv[1]);
+    return (FALSE);
+  }
+  /* get astrometry information */
+  strcpy (coords.ctype, "NONE");
+  fits_scan (&header, "CTYPE1",   "%s",  1, coords.ctype);
+  if (strcmp (coords.ctype, "RA---PLY")) {
+    fprintf (stderr, "ERROR: wrong astrometric info in header\n");
+    return (FALSE);
+  }
+  fits_scan (&header, "CDELT1",   "%f", 1, &coords.cdelt1); 
+  fits_scan (&header, "CDELT2",   "%f", 1, &coords.cdelt2);
+  fits_scan (&header, "CRVAL1",   "%lf", 1, &coords.crval1);
+  fits_scan (&header, "CRVAL2",   "%lf", 1, &coords.crval2);  
+  fits_scan (&header, "CRPIX1",   "%f", 1, &coords.crpix1);
+  fits_scan (&header, "CRPIX2",   "%f", 1, &coords.crpix2);
+  fits_scan (&header, "PC001001", "%f", 1, &coords.pc1_1);
+  fits_scan (&header, "PC001002", "%f", 1, &coords.pc1_2);
+  fits_scan (&header, "PC002001", "%f", 1, &coords.pc2_1);
+  fits_scan (&header, "PC002002", "%f", 1, &coords.pc2_2);
+  /* RA Terms */
+  fits_scan (&header, "PCA1X2Y0", "%f", 1, &coords.polyterms[0][0]);
+  fits_scan (&header, "PCA1X1Y1", "%f", 1, &coords.polyterms[1][0]);
+  fits_scan (&header, "PCA1X0Y2", "%f", 1, &coords.polyterms[2][0]);
+  fits_scan (&header, "PCA1X3Y0", "%f", 1, &coords.polyterms[3][0]);
+  fits_scan (&header, "PCA1X2Y1", "%f", 1, &coords.polyterms[4][0]);
+  fits_scan (&header, "PCA1X1Y2", "%f", 1, &coords.polyterms[5][0]);
+  fits_scan (&header, "PCA1X0Y3", "%f", 1, &coords.polyterms[6][0]);
+  /* Dec Terms */			    
+  fits_scan (&header, "PCA2X2Y0", "%f", 1, &coords.polyterms[0][1]);
+  fits_scan (&header, "PCA2X1Y1", "%f", 1, &coords.polyterms[1][1]);
+  fits_scan (&header, "PCA2X0Y2", "%f", 1, &coords.polyterms[2][1]);
+  fits_scan (&header, "PCA2X3Y0", "%f", 1, &coords.polyterms[3][1]);
+  fits_scan (&header, "PCA2X2Y1", "%f", 1, &coords.polyterms[4][1]);
+  fits_scan (&header, "PCA2X1Y2", "%f", 1, &coords.polyterms[5][1]);
+  fits_scan (&header, "PCA2X0Y3", "%f", 1, &coords.polyterms[6][1]);
+  coords.Npolyterms = 2; /* how many do we use? */
+
+  /* find number of stars */
+  fits_scan (&header, "NSTARS", "%d", 1, &Nstars);
+  if (Nstars == 0) {
+    fprintf (stderr, "no stars in file\n");
+    return (FALSE);
+  }
+
+  /* open file data */
+  f = fopen (argv[1], "r");
+  if (f == NULL) {
+    fprintf (stderr, "can't find data in file %s\n", argv[1]);
+    return (FALSE);
+  }
+  fseek (f, header.size, SEEK_SET); 
+
+  /* set up storage buffers */
+  Xvec.Nelements = Nstars;
+  Yvec.Nelements = Nstars;
+  Zvec.Nelements = Nstars;
+  ALLOCATE (Xvec.elements, float, Xvec.Nelements);
+  ALLOCATE (Yvec.elements, float, Yvec.Nelements);
+  ALLOCATE (Zvec.elements, float, Zvec.Nelements);
+  ALLOCATE (buffer, char, (BLOCK*BYTES_STAR));
+
+  /* load in stars by blocks of 1000 */
+  nstars = 0;
+  Nbytes = Nstars*BYTES_STAR;
+  for (i = 0; i < (int)(Nbytes / (BLOCK*BYTES_STAR)); i++) {
+    nbytes = fread (buffer, 1, (BLOCK*BYTES_STAR), f);
+    if (nbytes != BLOCK*BYTES_STAR) {
+      fprintf (stderr, "failed to read in stars (1)\n");
+      free (Xvec.elements);
+      free (Yvec.elements);
+      free (Zvec.elements);
+      free (buffer);
+      return (FALSE);
+    }
+    for (j = 0; j < BLOCK; j++, nstars++) {
+      dparse (&X,  1, &buffer[j*BYTES_STAR]);
+      dparse (&Y,  2, &buffer[j*BYTES_STAR]);
+      dparse (&M,  3, &buffer[j*BYTES_STAR]);
+      XY_to_RD (&R, &D, X, Y, &coords);
+      fRD_to_XY (&Xvec.elements[nstars], &Yvec.elements[nstars], R, D, &graphmode.coords);
+      Zvec.elements[nstars] = MIN (1.0, MAX (0.01, (M - zero) / range));
+    }
+  }
+  /* left over fraction of a block */
+  nbytes = fread (buffer, 1, (Nbytes % (BLOCK*BYTES_STAR)), f);
+  if (nbytes != (Nbytes % (BLOCK*BYTES_STAR))) {
+    fprintf (stderr, "ERROR: failed to read in stars (2)\n");
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+    free (buffer);
+    return (FALSE);
+  }
+  for (j = 0; j < nbytes / BYTES_STAR; j++, nstars++) {
+    dparse (&X,  1, &buffer[j*BYTES_STAR]);
+    dparse (&Y,  2, &buffer[j*BYTES_STAR]);
+    dparse (&M,  3, &buffer[j*BYTES_STAR]);
+    XY_to_RD (&R, &D, X, Y, &coords);
+    fRD_to_XY (&Xvec.elements[nstars], &Yvec.elements[nstars], R, D, &graphmode.coords);
+    Zvec.elements[nstars] = MIN (1.0, MAX (0.01, (M - zero) / range));
+  }
+  
+  if (nstars != Nstars) {
+    fprintf (stderr, "ERROR: failed to read in all stars (%d of %d)\n", nstars, Nstars);
+    free (Xvec.elements);
+    free (Yvec.elements);
+    free (Zvec.elements);
+    free (buffer);
+    return (FALSE);
+  }
+
+  graphmode.style = 2;
+  graphmode.size = -1;
+  graphmode.etype = 0;
+  Npts = Xvec.Nelements;
+  PrepPlotting (Npts, &graphmode);
+
+  PlotVector (Npts, Xvec.elements);
+  PlotVector (Npts, Yvec.elements);
+  PlotVector (Npts, Zvec.elements);
+
+  free (Xvec.elements);
+  free (Yvec.elements);
+  free (Zvec.elements);
+  free (buffer);
+
+  return (TRUE);
+
+}
+
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/skycoverage.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/skycoverage.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/skycoverage.c	(revision 21703)
@@ -0,0 +1,157 @@
+# include "dvo1.h"
+
+int skycoverage (int argc, char **argv) {
+
+  int i, N, Nimage, status, TimeSelect, ByName, xs, ys;
+  time_t tzero, tend;
+  double pixscale, dPix, r, d, Xi, Yi, Xs, Ys, x[2], y[2], trange;
+  Image *image;
+  char name[256];
+  float *V;
+  int Nx, Ny;
+  Buffer *buf;
+  Coords coords;
+
+  ByName = FALSE;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    remove_argument (N, &argc, argv);
+    strcpy (name, argv[N]);
+    remove_argument (N, &argc, argv);
+    ByName = TRUE;
+  }
+
+  TimeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-time"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_dtime (argv[N], &trange)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+  if ((N = get_argument (argc, argv, "-trange"))) {
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tzero)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    if (!str_to_time (argv[N], &tend)) { 
+      fprintf (stderr, "syntax error\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
+    trange = tend - tzero;
+    if (trange < 0) {
+      trange = fabs (trange);
+      tzero -= trange;
+    }
+    TimeSelect = TRUE;
+  }
+ 
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: skycoverage (buffer) (pixscale) (dPix) [-time start range] [-name name]\n");
+    fprintf (stderr, "       (buffer) saves bitmapped AIT plot\n");
+    fprintf (stderr, "       (pixscale) specifies the pixel size in degrees\n");
+    fprintf (stderr, "       note: we need 64800 / (pixscale)^2 pixels to represent the sky\n");
+    return (FALSE);
+  }
+  
+  if ((buf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  pixscale = atof(argv[2]);
+  dPix     = atof(argv[3]);
+
+  Nx = 360/pixscale;
+  Ny = 180/pixscale;
+
+  buf[0].matrix.Naxis[0] = Nx;
+  buf[0].matrix.Naxis[1] = Ny;
+
+  /* I should encapsulate this in a create_default_buffer */
+  fits_free_matrix (&buf[0].matrix);
+  fits_free_header (&buf[0].header);
+  buf[0].header.bitpix = buf[0].bitpix = -32;
+  buf[0].header.unsign = buf[0].unsign = FALSE;
+  buf[0].header.bscale = buf[0].bscale = 1.0;
+  buf[0].header.bzero  = buf[0].bzero  = 0.0;
+  buf[0].header.Naxes = 2;
+  buf[0].header.Naxis[0] = Nx;
+  buf[0].header.Naxis[1] = Ny;
+  fits_create_header (&buf[0].header);
+  fits_create_matrix (&buf[0].header, &buf[0].matrix);
+
+  coords.crval1 = 180;
+  coords.crval2 = 0;
+  coords.crpix1 = 0.5*Nx;
+  coords.crpix2 = 0.5*Ny;
+  strcpy (coords.ctype, "DEC--AIT");
+  coords.pc1_1 = coords.pc2_2 = 1;
+  coords.pc1_2 = coords.pc2_1 = 0;
+  coords.cdelt1 = coords.cdelt2 = pixscale;
+  coords.Npolyterms = 0;
+
+  PutCoords (&coords, &buf[0].header);
+
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  V = (float *)buf[0].matrix.buffer;
+  bzero (V, Nx*Ny*sizeof(float));
+
+  for (ys = 0; ys < Ny; ys++) {
+    for (xs = 0; xs < Nx; xs++) {
+      status = XY_to_RD (&r, &d, (double)(xs), (double)(ys), &coords);
+      status &= (r > 0);
+      status &= (r < 360);
+      if (status) {
+	V[ys*Nx + xs] = 2;
+      }
+    }
+  }
+
+  for (i = 0; i < Nimage; i++) {
+    if (ByName && strcmp (name, image[i].name)) continue;
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+
+    /* project this image to screen display coords */
+    /* DIS images represent a field, not a chip */
+    if (!strcmp(&image[i].coords.ctype[4], "-DIS")) {
+      x[0] = -0.5*image[i].NX; y[0] = -0.5*image[i].NY;
+      x[1] = +0.5*image[i].NX; y[1] = +0.5*image[i].NY;
+    } else {
+      x[0] = 0;                y[0] = 0;
+      x[1] = image[i].NX;      y[1] = image[i].NY;
+    }
+    status = FALSE;
+    
+    for (Yi = y[0] + 0.5*dPix; Yi < y[1]; Yi += dPix) {
+      for (Xi = x[0] + 0.5*dPix; Xi < x[1]; Xi += dPix) {
+	XY_to_RD (&r, &d, Xi, Yi, &image[i].coords);
+	while (r <   0.0) { r += 360.0; }
+	while (r > 360.0) { r -= 360.0; }
+	status = RD_to_XY (&Xs, &Ys, r, d, &coords);
+	if (status) {
+	  xs = (int)Xs;
+	  ys = (int)Ys;
+	  V[ys*Nx + xs] = 1;
+	}
+      }
+    }
+  }
+
+  free (image);
+  return (TRUE);
+}
+
+
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/subpix.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/subpix.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/subpix.c	(revision 21703)
@@ -0,0 +1,193 @@
+# include "dvo1.h"
+
+int bracket (double *list, double value, int Nlist, int mode);
+
+int subpix (int argc, char **argv) {
+  
+  int i, j, I, Nlo, Nhi, Nentry, Nstars, Nregions, Nimage, Nmeasure;
+  int *index, *entry;
+  int Nmin, Nsub, NSUB, status;
+  int TimeFormat;
+  time_t Timage, TimeReference;
+  double X, Y, Mabs, t;
+  double Ra, Dec, Radius, Radius2, r, Rmin;
+  double *RA, *DEC;
+  char catdir[256], filename[256];
+  
+  Measure *measure;
+  Image *image;
+  RegionFile *regions;
+  Catalog catalog;
+
+  if (!InitPhotcodes ()) return (FALSE);
+
+  VarConfig ("CATDIR", "%s", catdir);
+  GetTimeFormat (&TimeReference, &TimeFormat);
+
+  if (argc != 4) {
+    fprintf (stderr, "USAGE: subpix ra dec radius\n");
+    return (FALSE);
+  }
+  if (!str_to_radec (&Ra, &Dec, argv[1], argv[2])) return (FALSE);
+  if (Ra < 0) Ra += 360.0;
+  if (Ra > 360.0) Ra -= 360.0;
+  Radius = atof (argv[3]);
+
+  /* load star nearest position */
+  regions = find_regions (Ra, Dec, Radius, &Nregions);
+  if (Nregions > 1) {
+    fprintf (stderr, "warning, radius overlaps region boundary, not yet implemented\n");
+  }
+
+  /* lock, load, unlock catalog */
+  sprintf (filename, "%s/%s", catdir, regions[0].name);
+  catalog.filename = filename;
+  switch (lock_catalog (&catalog, LCK_SOFT)) {
+  case 2:
+    unlock_catalog (&catalog);
+  case 0:
+    return (FALSE);
+  }
+  if (!load_catalog (&catalog, LOAD_AVES | LOAD_MEAS, TRUE)) {
+    unlock_catalog (&catalog);
+    return (FALSE);
+  }
+  unlock_catalog (&catalog);
+
+  /* quick search of star list for Ra, Dec */
+  Nstars = catalog.Naverage;
+  ALLOCATE (RA, double, Nstars);
+  ALLOCATE (DEC, double, Nstars);
+  ALLOCATE (index, int, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    RA[i] = catalog.average[i].R;
+    DEC[i] = catalog.average[i].D;
+    index[i] = i;
+  }
+  if (Nstars > 1) dsort_lists (DEC, RA, index, Nstars);
+
+  /* bracket the DEC range of interest */
+  Nlo = bracket (DEC, Dec - Radius, Nstars, FALSE);
+  Nhi = bracket (DEC, Dec + Radius, Nstars, TRUE);
+  ALLOCATE (entry, int, MAX (Nhi - Nlo, 1));
+  Nentry = 0;
+
+  /* find the list of stars */
+  Radius2 = Radius*Radius;
+  for (i = Nlo; i < Nhi; i++) {
+    r = SQ(Dec - DEC[i]) + SQ(Ra - RA[i]);
+    if (r < Radius2) {
+      entry[Nentry] = i;
+      Nentry ++;
+    }
+  }
+  if (!Nentry) {
+    fprintf (stderr, "no stars found\n");
+    free (RA);
+    free (DEC);
+    free (entry);
+    free (index);
+    if (catalog.average != 0) free (catalog.average);
+    if (catalog.measure != 0) free (catalog.measure);
+    free (regions);
+    return (TRUE);
+  }
+
+  /* find the closest star */
+  Nmin = 0;
+  Rmin = SQ(Dec - DEC[entry[0]]) + SQ(Ra - RA[entry[0]]);
+  for (i = 1; i < Nentry; i++) {
+    r = SQ(Dec - DEC[entry[i]]) + SQ(Ra - RA[entry[i]]);
+    if (r < Rmin) {
+      Rmin = r;
+      Nmin = i;
+    }
+  }
+  Nentry = index[entry[Nmin]];
+  Ra = RA[entry[Nmin]];
+  Dec = DEC[entry[Nmin]];
+  fprintf (stderr, "finding subpix values for star @ %f %f\n", Ra, Dec);
+
+  free (RA);
+  free (DEC);
+  free (entry);
+  free (index);
+
+  /* storage for the image references */
+  Nsub = 0;
+  NSUB = 100;
+  ALLOCATE (index, int, NSUB);
+
+  /* load all images, extract those touching Ra, Dec */
+  if ((image = LoadImages (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  for (i = 0; i < Nimage; i++) {
+    if (!FindMosaicForImage (image, Nimage, i)) continue;
+    status = RD_to_XY (&X, &Y, Ra, Dec, &image[i].coords);
+    if (!status || (X < 0) || (X > image[i].NX) || (Y < 0) || (Y > image[i].NY)) continue;
+    index[Nsub] = i;
+    Nsub ++;
+    if (Nsub == NSUB - 1) {
+      NSUB += 100;
+      REALLOCATE (index, int, NSUB);
+    }
+  }
+
+  /* only print the entries for existing measurements of this star */ 
+  measure = &catalog.measure[catalog.average[Nentry].offset];
+  Nmeasure = catalog.average[Nentry].Nm;
+  for (i = 0; i < Nsub; i++) {
+    I = index[i];
+    if (!FindMosaicForImage (image, Nimage, I)) continue;
+    Timage = image[I].tzero;
+    for (j = 0; j < Nmeasure; j++) {
+      if (measure[j].t == Timage) { 
+	Mabs = PhotCat (&measure[j]);
+	RD_to_XY (&X, &Y, Ra, Dec, &image[I].coords);
+	t = TimeValue (measure[j].t, TimeReference, TimeFormat);
+	fprintf (GetOutfile(), "%f %6.3f %7.2f %7.2f %5.3f\n", t, Mabs, X, Y, 0.001*image[I].secz);
+      } 
+    }
+  }
+
+  if (catalog.average != 0) free (catalog.average);
+  if (catalog.measure != 0) free (catalog.measure);
+  free (image);
+  free (index);
+  free (regions);
+
+  return (TRUE);
+}
+
+/* fast operation to find an entry just below (0) or above (1) value */
+int bracket (double *list, double value, int Nlist, int mode) {
+
+  int Nlo, Nhi, N;
+
+  if (mode == 0) {
+    Nlo = 0; Nhi = Nlist;
+    while (Nhi - Nlo > 10) {
+      N = 0.5*(Nlo + Nhi);
+      if (list[N] < value) {
+	Nlo = N;
+      } else {
+	Nhi = N + 1;
+      }
+    }
+    return (Nlo);
+  }
+  if (mode == 1) {
+    Nlo = 0; Nhi = Nlist;
+    while (Nhi - Nlo > 10) {
+      N = 0.5*(Nlo + Nhi);
+      if (list[N] > value) {
+	Nhi = N;
+      } else {
+	Nlo = N - 1;
+      }
+    }
+    return (Nhi);
+  }
+  return (0);
+}
Index: /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/version.c
===================================================================
--- /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/version.c	(revision 21703)
+++ /tags/ohana/dvo-0-1/Ohana/src/opihi/dvo/version.c	(revision 21703)
@@ -0,0 +1,14 @@
+# include "dvo1.h"
+static char *name = "$Name: not supported by cvs2svn $";
+
+int version (int argc, char **argv) {
+
+  fprintf (stderr, "%s\n", name);
+
+  fprintf (stderr, "%s\n", opihi_version());
+  fprintf (stderr, "%s\n", ohana_version());
+  fprintf (stderr, "%s\n", fits_version());
+
+  fprintf (stderr, "compiled on %s %s\n", __DATE__, __TIME__);
+  return (TRUE);
+}
