Index: /trunk/Ohana/src/addstar/test/delstar.dvo
===================================================================
--- /trunk/Ohana/src/addstar/test/delstar.dvo	(revision 34749)
+++ /trunk/Ohana/src/addstar/test/delstar.dvo	(revision 34749)
@@ -0,0 +1,412 @@
+# -*-sh-*-
+
+# relphot can set some secfilt values base on stack properties
+# we would like to test that these are correctly set
+
+input tap.dvo
+
+# set globals
+if (not($?PLOT)) set PLOT = 0 
+if (not($?FSUBSET)) set FSUBSET = 0.5
+
+# set various global variables
+macro init
+  $RA_CENTER = 10.0
+  $DEC_CENTER = 20.0
+  $PLATE_SCALE = 0.25
+  $NSEASON = 3
+  $NFILTER = 3
+  $NCHIP_X = 2
+  $NCHIP_Y = 2
+  $NCELL_X = 2
+  $NCELL_Y = 2
+  $CHIP_DX = 1000
+  $CHIP_DY = 1000
+
+  # images are loaded into dvo with GPC1 photcodes, so we need to get the nominal zps for those filters
+  $zpt_nominal:g = 24.58
+  $zpt_nominal:r = 24.80
+  $zpt_nominal:i = 24.74
+  $zpt_nominal:z = 24.26
+  $zpt_nominal:y = 23.41
+
+  # klam is negative, so klam*(airmass - 1) increase the zero point
+  $klam_nominal:g = -0.15
+  $klam_nominal:r = -0.10
+  $klam_nominal:i = -0.04
+  $klam_nominal:z = -0.03
+  $klam_nominal:y = -0.03
+
+  # photcode values for use elsewhere
+  $photcode_value:g = 11000
+  $photcode_value:r = 11100
+  $photcode_value:i = 11200
+  $photcode_value:z = 11300
+  $photcode_value:y = 11400
+end
+
+macro go
+  if ($0 != 3)
+    echo "go (fileroot) (catdir)"
+    break
+  end
+
+  local i fileroot rootdir catdir
+
+  $fileroot = $1
+  $catdir = $2
+
+  dirname $1 -var rootdir
+  mkdir $rootdir
+
+  init
+  mkstars 500
+
+  # tapPLAN {((mjd_uc[]*4 + mjd_nc[]*4) + (mjd_uc[] + mjd_nc[]) + (mjd_uc[] + mjd_nc[])) / 3}
+
+  # generate the basic images and check they were correctly ingested by dvo
+  if (1)
+    exec rm -rf $catdir
+    mksequence $fileroot $catdir
+  else
+    echo "*** temporarily skip data creation ***"
+  end
+
+  # size of region of interest in linear arcseconds
+  local RA_RANGE DEC_RANGE
+  $RA_RANGE  = 1.25 * $CHIP_DX * $NCHIP_X * $PLATE_SCALE
+  $DEC_RANGE = 1.25 * $CHIP_DY * $NCHIP_Y * $PLATE_SCALE 
+  $RA_MIN = $RA_CENTER  - $RA_RANGE  * 0.5 / 3600 / dcos ($DEC_CENTER)
+  $RA_MAX = $RA_CENTER  + $RA_RANGE  * 0.5 / 3600 / dcos ($DEC_CENTER)
+  $DEC_MIN = $DEC_CENTER - $DEC_RANGE * 0.5 / 3600
+  $DEC_MAX = $DEC_CENTER + $DEC_RANGE * 0.5 / 3600
+
+  # to test the deletion, extract measurements before and after delstar is called
+  catdir $catdir
+  skyregion $RA_MIN $RA_MAX $DEC_MIN $DEC_MAX
+
+  mextract ra dec mag photcode
+  set ra_all       = ra
+  set dec_all      = dec
+  set mag_all      = mag
+  set photcode_all = photcode
+  
+  imextract RA DEC PHOTCODE 
+  set ra_im_all  = RA
+  set dec_im_all = DEC
+  set pc_im_all  = PHOTCODE
+
+  echo "sleep to ensure mtime values are different"
+  sleep 2
+
+  echo delstar -D CATDIR $catdir -v -region $RA_MIN $RA_MAX $DEC_MIN $DEC_MAX -photcodes GPC1.r.SkyChip
+  exec delstar -D CATDIR $catdir -v -region $RA_MIN $RA_MAX $DEC_MIN $DEC_MAX -photcodes GPC1.r.SkyChip
+  echo done with delstar
+
+  mextract ra dec mag photcode
+  set ra_del       = ra
+  set dec_del      = dec
+  set mag_del      = mag
+  set photcode_del = photcode
+
+  imextract RA DEC PHOTCODE 
+  set ra_im_del  = RA
+  set dec_im_del = DEC
+  set pc_im_del  = PHOTCODE
+
+  # check the measurements
+  subset ra_r = ra_all if (photcode_all == $photcode_value:r)
+  tapOK {ra_r[] == (ra_all[] - ra_del[])} "deleted ra_r[] r-band measurements"
+
+  foreach filter g i z y
+    subset ra_0 = ra_all if (photcode_all == $photcode_value:$filter)
+    subset ra_1 = ra_del if (photcode_del == $photcode_value:$filter)
+    tapOK {ra_0[] == ra_1[]} "number of $filter-band measurements unchanged"
+
+    sort ra_0
+    sort ra_1
+    set dra = ra_0 - ra_1
+    vstat -q dra
+    tapOK {abs($MEAN)  < 0.000001} "$filter-band RA measurements unchanged"
+    tapOK {abs($SIGMA) < 0.000001} "$filter-band RA measurements unchanged"
+  end
+
+  # check the images
+  subset ra_r = ra_im_all if (pc_im_all == $photcode_value:r)
+  tapOK {ra_r[] == (ra_im_all[] - ra_im_del[])} "deleted ra_r[] r-band images"
+
+  foreach filter g i z y
+    subset ra_0 = ra_im_all if (pc_im_all == $photcode_value:$filter)
+    subset ra_1 = ra_im_del if (pc_im_del == $photcode_value:$filter)
+    tapOK {ra_0[] == ra_1[]} "number of $filter-band images unchanged"
+
+    set dra = ra_0 - ra_1
+    vstat -q dra
+    tapOK {abs($MEAN)  < 0.000001} "$filter-band RA images unchanged"
+    tapOK {abs($SIGMA) < 0.000001} "$filter-band RA images unchanged"
+  end
+end
+
+macro go.delstar
+
+  foreach filter g r i z y
+    ckexposure $catdir mjd_uc[$i] zpt_uc[$i] exptime_uc[$i] airmass_uc[$i] $filt_uc:$i raw
+  end
+
+  # run relphot on the db and check that the images now match the expected values
+  exec relphot g,r,i,z,y -v -region 9.5 10.5 19.5 20.5 -D CATDIR $catdir -nloop 0 -update >& tmp.log
+  foreach filter g r i z y
+    ckexposure catdir.test mjd_uc[$i] zpt_uc[$i] exptime_uc[$i] airmass_uc[$i] $filt_uc:$i relphot
+  end
+
+  tapDONE
+end
+
+# go testdata/t1 catdir.test
+# ckexposure catdir.test mjd_uc[0] zpt_uc[0] raw : result is mean of 0.0 (since test corrects for ZPT_NOMINAL vs REAL)
+# ckexposure catdir.test mjd_nc[0] zpt_nc[0] raw : result is mean of 0.0 
+# setphot -update -ubercal testzpt.fits -D CATDIR catdir.test
+# ckexposure catdir.test mjd_uc[0] zpt_uc[0] corr : result is mean of 0.0 (since image is corrected to ZPT_REAL)
+# ckexposure catdir.test mjd_nc[0] zpt_nc[0] corr : result is mean of -0.42 (since image is NOT corrected to ZPT_REAL)
+# relphot g -region 9.5 10.5 19.5 20.5 -update -D CATDIR catdir.test -D STAR_TOOFEW 1 -D SIGMA_LIM 0.075 -statmode MEAN
+# dvo: ckexposure catdir.test mjd_uc[0] zpt_uc[0] corr
+#  mean is now -0.42
+# dvo: ckexposure catdir.test mjd_nc[0] zpt_nc[0] corr
+#  mean is now -0.42 
+#  ** setphot assigned the zero point of the uc exposure to an effective -0.4 (ie, negative clouds), relphot was not told to keep this so it dragged the negative clouds to 0.0 -- this seems to be the right thing to do
+
+# re-run setphot, then relphot with -keep-ubercal
+
+# the test case has only 2 exposures, so the STAR_TOOFEW of 1 is necessary.  Also, the mag and sigma distributions are somewhat artificial
+# relphot g -v -region 9.5 10.5 19.5 20.5 -D CATDIR catdir.test -D STAR_TOOFEW 1 -D SIGMA_LIM 0.07 -statmode WT_MEAN -cloud-limit 0.5 -keep-ubercal -D IMAGE_OFFSET 0.5 -update
+# dvo: ckexposure catdir.test mjd_uc[0] zpt_uc[0] corr
+#  mean is now 0.0 
+# dvo: ckexposure catdir.test mjd_nc[0] zpt_nc[0] corr
+#  mean is now 0.0
+#  ** setphot correctly assigned the zero point of UC & relphot adjusted NC to match
+
+macro ckexposure
+  if ($0 != 8)
+    echo "ckexposure (catdir) (mjd) (zpt) (exptime) (airmass) (filter) (mode)"
+    echo "  mode == raw or corr"
+    break
+  end
+
+  local CATDIR MJD_IMAGE ZPT_REAL ZPT_NOMINAL EXPTIME FILTER AIRMASS
+  
+  $CATDIR      = $1
+  $MJD_IMAGE   = $2
+  $ZPT_REAL    = $3
+  $EXPTIME     = $4
+  $AIRMASS     = $5
+  $FILTER      = $6
+  $MODE        = $7
+
+  # XXX need a function to extract the nominal zpt for a given filter / photcode from the db
+  $ZPT_NOMINAL = $zpt_nominal:$FILTER
+  $KLAM_NOMINAL = $klam_nominal:$FILTER
+
+  $TIMEFORMAT = mjd
+  $TIMEREF = 0.0
+
+  catdir $CATDIR
+
+  # assume we still have stars_ra, stars_dec, stars_mag in hand
+  if ($PLOT)
+    dev -n 0
+    region $RA_CENTER $DEC_CENTER 0.2
+    images
+    pmeasure -all -m 15 20
+  end
+
+  skyregion {$RA_CENTER - 0.2/dcos($DEC_CENTER)} {$RA_CENTER + 0.2/dcos($DEC_CENTER)} {$DEC_CENTER - 0.2} {$DEC_CENTER + 0.2} 
+  mextract ra dec mag xccd yccd where (abs(time - $MJD_IMAGE) < 0.0001)
+ 
+  match2d -closest ra dec stars_ra stars_dec 0.001 -index1 index1 -index2 index2
+
+  reindex stars_ra_m  = stars_ra  using index1
+  reindex stars_dec_m = stars_dec using index1
+  reindex stars_mag_m = stars_mag using index1
+  set dr = 3600*(ra - stars_ra_m)
+  set dd = 3600*(dec - stars_dec_m)
+  set dm = mag - stars_mag_m
+
+  if ($PLOT) 
+    dev -n 1
+    lim mag dm; clear; box; plot mag dm
+  end
+
+  set cell_xbin = int(xccd / ($CHIP_DX / $NCELL_X))
+  set cell_ybin = int(yccd / ($CHIP_DY / $NCELL_Y))
+  subset dm00 = dm if (cell_xbin == 0) && (cell_ybin == 0)
+  subset dm01 = dm if (cell_xbin == 0) && (cell_ybin == 1)
+  subset dm10 = dm if (cell_xbin == 1) && (cell_ybin == 0)
+  subset dm11 = dm if (cell_xbin == 1) && (cell_ybin == 1)
+
+  # uncorrected values behave like this:
+  #   mag_DVO  = m_inst + zpt_nominal + 2.5*log(exptime) + K*(airmass - 1.0)
+  #   mag_real = m_inst + zpt_real + cell_offset
+  #   dm = mag_DVO - mag_real = zpt_nominal - zpt_real - cell_offset
+  #   <dm> - zpt_nominal + zpt_real + cell_offset ~ 0.0
+  #   zpt_real (in this case) = 25.0  + 2.5*log(exptime) + K*(airmass - 1.0) 
+  #     (actually, it is the value in the vector 'zpt' for this entry
+  #   zpt_nominal = 24.58
+
+  # setphot-corrected values behave like this:
+  #   mag_DVO  = mag_real (because m_inst has cell_offset applied)
+  #   dm = mag_DVO - mag_real ~ 0.0
+
+  $ZPT_REAL_NORM = $ZPT_REAL - 2.5*log($EXPTIME) - $KLAM_NOMINAL*($AIRMASS - 1.0)
+
+  if ("$MODE" == "raw") 
+    for ix 0 $NCELL_X
+      for iy 0 $NCELL_Y
+        # vstat -q dm$ix\$iy
+        # echo cell_off[$ix][$iy] {$MEDIAN - $ZPT_NOMINAL + $ZPT_REAL + cell_off[$ix][$iy]} $MEDIAN $MEAN $SIGMA 
+  
+        set dm_adjust = dm$ix\$iy - $ZPT_NOMINAL + $ZPT_REAL_NORM + cell_off[$ix][$iy]
+        vstat -q dm_adjust
+        tapOK {abs($MEAN) < 0.005} "addstar raw ZP $MJD_IMAGE $FILTER"
+      end
+    end
+    return
+  end
+
+  if ("$MODE" == "setphot_uc") 
+    vstat -q dm
+    tapOK {abs($MEAN) < 0.005} "setphot_uc  ZP $MJD_IMAGE $FILTER"
+    return
+  end
+
+  if ("$MODE" == "setphot_nc") 
+    vstat -q dm
+    tapOK {abs($MEAN - $ZPT_NOMINAL + $ZPT_REAL_NORM) < 0.005} "setphot_nc  ZP $MJD_IMAGE $FILTER"
+    return
+  end
+
+  if ("$MODE" == "relphot") 
+    vstat -q dm
+    tapOK {abs($MEAN) < 0.005} "relphot    ZP $MJD_IMAGE $FILTER"
+    return
+  end
+
+end
+
+macro mksequence
+  if ($0 != 3)
+    echo "mksequence (fileroot) (catdir)"
+    break
+  end
+
+  local i
+
+  # basic set of 5 stacks
+  foreach filter g r i z y
+    mkstack $1.$filter $RA_CENTER $DEC_CENTER $zpt_nominal:$filter 100.0 1.0 56228.666146 $filter $2
+  end
+end
+
+macro mkstack
+ if ($0 != 10)
+   echo "mkstack (fileroot) (ra) (dec) (zpt) (exptime) (airmass) (mjd) (filter) (catdir)"
+   break
+ end
+
+ local ix iy date time datetime ra dec ROOT RAo DECo ZPT MJD FILTER EXPTIME AIRMASS CATDIR
+
+ $ROOT    = $1
+ $RAo     = $2
+ $DECo    = $3
+ $ZPT     = $4
+ $EXPTIME = $5
+ $AIRMASS = $6 
+ $MJD     = $7
+ $FILTER  = $8
+ $CATDIR  = $9
+
+ $TIMEFORMAT = mjd
+ $TIMEREF = 0.0
+
+ for ix 0 $NCHIP_X
+  for iy 0 $NCHIP_Y
+    $dx  = $CHIP_DX * $PLATE_SCALE * ($ix - 0.5*$NCHIP_X + 0.5)
+    $dy  = $CHIP_DY * $PLATE_SCALE * ($iy - 0.5*$NCHIP_Y + 0.5)
+    $ra  = $RAo  - $dx / 3600.0 / dcos($DECo)
+    $dec = $DECo - $dy / 3600.0
+    # echo $ra $dec $dx $dy
+    mkinput test.in.txt $ra $dec $ZPT $FSUBSET
+    
+    # ra,dec is the center of this chip
+    local options
+    $options = 
+    $options = $options -radec $ra $dec 
+    $options = $options -type PS1_V4
+    $options = $options -coords 
+    $options = $options -photcode GPC1.$FILTER.SkyChip 
+    $options = $options -no-noise 
+    $options = $options -size $CHIP_DX $CHIP_DY 
+    $options = $options -crpix {0.5*$CHIP_DX} {0.5*$CHIP_DY} 
+    $options = $options -exptime $EXPTIME
+
+    # these should not be needed for stacks, right
+    $options = $options -airmass $AIRMASS
+    $options = $options -mjd $MJD 
+
+    exec mkcmf test.in.txt $ROOT.$ix.$iy.cmf $options
+    echo mkcmf test.in.txt $ROOT.$ix.$iy.cmf $options 
+    
+    # the fake images have inconsistent ra,dec and airmass,sidtime values
+    echo addstar $ROOT.$ix.$iy.cmf -D CATDIR $CATDIR -D CATFORMAT PS1_V4 -D CAMERA gpc1 -quick-airmass
+    exec addstar $ROOT.$ix.$iy.cmf -D CATDIR $CATDIR -D CATFORMAT PS1_V4 -D CAMERA gpc1 -quick-airmass >& tmp.log
+  end
+ end
+end
+
+# make a simple input file for mkcmf
+macro mkinput
+  if ($0 != 6)
+    echo "mkinput (filename) (ra) (dec) (zpt) (fSubset)"
+    break
+  end
+
+  # chip coordinate of the stars
+  # ra,dec is at the chip center, which corresponds to pixel (CHIP_DX,CHIP_DY)/2
+  set stars_X = (stars_ra  - $2) * 3600.0 * dcos($3) / $PLATE_SCALE + $CHIP_DX*0.5
+  set stars_Y = (stars_dec - $3) * 3600.0            / $PLATE_SCALE + $CHIP_DY*0.5
+  set stars_M = (stars_mag - $4)
+
+  # a random number to generate a random subset
+  set fkeep = rnd(stars_ra)
+  set valid = (stars_X > 0) && (stars_X < $CHIP_DX) && (stars_Y > 0) && (stars_Y < $CHIP_DX) && (fkeep < $5)
+  subset stars_x  = stars_X if valid
+  subset stars_y  = stars_Y if valid
+  subset stars_mi = stars_M if valid
+  subset stars_r  = stars_ra if valid
+  subset stars_d  = stars_dec if valid
+  subset stars_mr = stars_mag if valid
+
+  write -f "%10.6f %10.6f %7.3f  %6.1f %6.1f %7.3f" $1 stars_r stars_d stars_mr stars_x stars_y stars_mi
+end
+
+# generate a set of stars with raw RA, DEC, MAG values to use for all of the output cmf files
+macro mkstars
+  if ($0 != 2)
+    echo "USAGE: mkstars (Nstars)"
+    break
+  end
+
+  local RA_RANGE DEC_RANGE
+
+  # the images are oriented along N-S, E-W lines
+
+  # size of region of interest in linear arcseconds
+  $RA_RANGE  = 1.25 * $CHIP_DX * $NCHIP_X * $PLATE_SCALE
+  $DEC_RANGE = 1.25 * $CHIP_DY * $NCHIP_Y * $PLATE_SCALE 
+
+  create tmp 0 $1
+  set stars_ra  = $RA_CENTER  + $RA_RANGE  * (rnd(tmp) - 0.5) / 3600 / dcos ($DEC_CENTER)
+  set stars_dec = $DEC_CENTER + $DEC_RANGE * (rnd(tmp) - 0.5) / 3600
+  set stars_mag = 15.0 + 4.0 * rnd(tmp) 
+
+  # stars_ra,dec,mag are the true positions and mags of the stars
+end
Index: /trunk/Ohana/src/delstar/Makefile
===================================================================
--- /trunk/Ohana/src/delstar/Makefile	(revision 34748)
+++ /trunk/Ohana/src/delstar/Makefile	(revision 34749)
@@ -1,3 +1,3 @@
-default: delstar
+default: delstar delstar_client
 help:
 	@echo "make options: addstar (default)"
@@ -18,5 +18,7 @@
 
 delstar: $(BIN)/delstar.$(ARCH)
-install: $(DESTBIN)/delstar
+delstar_client: $(BIN)/delstar_client.$(ARCH)
+
+install: $(DESTBIN)/delstar $(DESTBIN)/delstar_client
 
 DELSTAR = \
@@ -27,4 +29,6 @@
 $(SRC)/delete_imagename.$(ARCH).o \
 $(SRC)/delete_imagefile.$(ARCH).o \
+$(SRC)/delete_image_photcodes.$(ARCH).o \
+$(SRC)/delete_photcodes.$(ARCH).o \
 $(SRC)/delete_times.$(ARCH).o 	  \
 $(SRC)/gimages.$(ARCH).o   	  \
@@ -33,4 +37,12 @@
 $(SRC)/parse_time.$(ARCH).o       \
 $(SRC)/check_permissions.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o          
+
+DELSTAR_CLIENT = \
+$(SRC)/delstar_client.$(ARCH).o   \
+$(SRC)/SetSignals.$(ARCH).o       \
+$(SRC)/ConfigInit.$(ARCH).o 	  \
+$(SRC)/args.$(ARCH).o	          \
+$(SRC)/delete_photcodes.$(ARCH).o \
 $(SRC)/Shutdown.$(ARCH).o          
 
@@ -42,2 +54,5 @@
 $(DELSTAR): $(INC)/delstar.h
 $(BIN)/delstar.$(ARCH) : $(DELSTAR)
+
+$(DELSTAR_CLIENT): $(INC)/delstar.h
+$(BIN)/delstar_client.$(ARCH) : $(DELSTAR_CLIENT)
Index: /trunk/Ohana/src/delstar/doc/delete_photcodes.txt
===================================================================
--- /trunk/Ohana/src/delstar/doc/delete_photcodes.txt	(revision 34749)
+++ /trunk/Ohana/src/delstar/doc/delete_photcodes.txt	(revision 34749)
@@ -0,0 +1,33 @@
+
+2012.11.21
+
+I'm working on the code to delete a subset of photcodes.  I'm
+basically re-writing the delstar core code because I don't trust this
+old stuff to work any more.
+
+But, I'm getting myself confused, so I need to map this out:
+
+we start with Measure, Average, where
+
+ measure[i].averef -> average[averef]
+ measure[i].objID   = average[averef].objID
+ measure[i].catID   = average[averef].catID
+
+I am not assuming the input Measure array is sorted (in averef order)
+
+Generate the following arrays:
+
+given measure[i], average[averef] in arbitrary order:
+
+n = measureSeqRaw[i] : measure[n] is in averef order (after sort)
+
+n = measureSeqOut[i] : measure[n] in averef order, only valid measurements
+
+n = measureAveRaw[i] : average[n] is matching entry (just an array of the averefs)
+
+averageNmeas[i] : number of measurements after filtering
+
+averageSeqOut[i] : new averef sequence after filtering
+
+n = measureAveOut[i] : average[n] is matching entry, only valid measurements
+
Index: /trunk/Ohana/src/delstar/include/delstar.h
===================================================================
--- /trunk/Ohana/src/delstar/include/delstar.h	(revision 34748)
+++ /trunk/Ohana/src/delstar/include/delstar.h	(revision 34749)
@@ -12,11 +12,16 @@
 
 /* global variables set in parameter file */
-char   ImageCat[256];
-char   ImageTemplate[256];
-char   CatTemplate[256];
-char   GSCFILE[256];
-char   CATDIR[256];
+char   ImageCat[DVO_MAX_PATH];
+char   ImageTemplate[DVO_MAX_PATH];
+char   CatTemplate[DVO_MAX_PATH];
+char   GSCFILE[DVO_MAX_PATH];
+
+char  *CATDIR;
+
 char   CATMODE[16];    /* raw, mef, split, mysql */
 char   CATFORMAT[16];  /* internal, elixir, loneos, panstarrs */
+
+char  *IMAGENAME;
+
 double NSIGMA;
 double ALPHA;
@@ -24,6 +29,13 @@
 int    ORPHAN;
 int    MISSED;
-char   SKY_TABLE[256];
+char   SKY_TABLE[DVO_MAX_PATH];
 int    SKY_DEPTH;  /** XXX EAM : depth of catalog tables, fix usage */
+
+int    PARALLEL;
+int    PARALLEL_MANUAL;
+int    PARALLEL_SERIAL;
+
+int          HOST_ID;
+char        *HOSTDIR;
 
 time_t    START;
@@ -31,8 +43,12 @@
 PhotCode *PHOTCODE;
 
+char *PHOTCODE_LIST;
+
 int    MODE;
-enum {MODE_IMAGENAME, MODE_IMAGEFILE, MODE_TIME, MODE_ORPHAN, MODE_MISSED};
+enum {MODE_NONE, MODE_IMAGENAME, MODE_IMAGEFILE, MODE_TIME, MODE_ORPHAN, MODE_MISSED, MODE_PHOTCODES};
 
 char DateKeyword[64], DateMode[64], UTKeyword[64], MJDKeyword[64], JDKeyword[64];
+
+SkyRegion UserPatch;
 
 /*** delstar prototypes ***/
@@ -46,8 +62,8 @@
 int        Shutdown               PROTO((char *format, ...)) OHANA_FORMAT(printf, 1, 2);
 void       TrapSignal             PROTO((int sig));
-int        args                   PROTO((int *argc, char **argv));
+int        args                   PROTO((int argc, char **argv));
 void       check_permissions      PROTO((char *basefile));
-void       delete_imagefile       PROTO((FITS_DB *db, char *filename));
-void       delete_imagename       PROTO((FITS_DB *db, char *name));
+void       delete_imagefile       PROTO((FITS_DB *db));
+void       delete_imagename       PROTO((FITS_DB *db));
 void       delete_times           PROTO((FITS_DB *db));
 int        edge_check             PROTO((double *x1, double *y1, double *x2, double *y2));
@@ -72,2 +88,11 @@
 
 void set_db (FITS_DB *in);
+
+int args_client (int argc, char **argv);
+
+void SortAveMeasMatch (off_t *MEAS, off_t *AVE, off_t N);
+
+int delete_photcodes (int hostID, char *hostpath);
+int delete_photcodes_parallel (SkyList *sky);
+int delete_photcodes_catalog (Catalog *catalog, PhotCode **photcodes, int Nphotcodes);
+int delete_image_photcodes (FITS_DB *db);
Index: /trunk/Ohana/src/delstar/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/delstar/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/delstar/src/ConfigInit.c	(revision 34749)
@@ -5,5 +5,4 @@
   char *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -20,10 +19,15 @@
   ScanConfig (config, "ALPHA",                  "%lf", 0, &ALPHA);
   ScanConfig (config, "GSCFILE",                "%s", 0, GSCFILE);
-  ScanConfig (config, "CATDIR",                 "%s", 0, CATDIR);
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
 
-  sprintf (ImageCat, "%s/Images.dat", CATDIR);
+  // force CATDIR to be absolute (so parallel mode will work)
+  char *tmpcatdir = NULL;
+  ALLOCATE (tmpcatdir, char, DVO_MAX_PATH);
+  ScanConfig (config, "CATDIR",                 "%s",  0, tmpcatdir);
+  CATDIR = abspath (tmpcatdir, DVO_MAX_PATH);
+  free (tmpcatdir);
+
+  snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", CATDIR);
 
   ScanConfig (config, "DATE-KEYWORD",           "%s", 0, DateKeyword);
@@ -45,6 +49,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/delstar/src/args.c
===================================================================
--- /trunk/Ohana/src/delstar/src/args.c	(revision 34748)
+++ /trunk/Ohana/src/delstar/src/args.c	(revision 34749)
@@ -4,6 +4,6 @@
 
   fprintf (stderr, "USAGE:\n");
-  fprintf (stderr, "  delstar (filename)\n");
-  fprintf (stderr, "  delstar -name (filename)\n");
+  fprintf (stderr, "  delstar -file (filename)\n");
+  fprintf (stderr, "  delstar -name (imagename)\n");
   fprintf (stderr, "  delstar -time (start) (stop/range)\n");
   fprintf (stderr, "  delstar -orphan (region)\n");
@@ -22,5 +22,10 @@
 }
 
-int args (int *argc, char **argv) {
+void delstar_client_usage () {
+  fprintf (stderr, "USAGE: delstar_client [options]\n");
+  exit (2);
+}
+
+int args (int argc, char **argv) {
   
   int N;
@@ -28,38 +33,100 @@
 
   /* check for help request */
-  if (get_argument (*argc, argv, "-help") ||
-      get_argument (*argc, argv, "-h")) {
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
     help ();
   }
 
   VERBOSE = FALSE;
-  if ((N = get_argument (*argc, argv, "-v"))) {
+  if ((N = get_argument (argc, argv, "-v"))) {
     VERBOSE = TRUE;
-    remove_argument (N, argc, argv);
-  }
-
-  MODE = MODE_IMAGEFILE;
-  if ((N = get_argument (*argc, argv, "-name"))) {
-    if (MODE != MODE_IMAGEFILE) usage();
+    remove_argument (N, &argc, argv);
+  }
+
+  // region of interest
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  // XXX for the moment, make this selection manual.  it needs to be automatic 
+  // based on the state of the SkyTable
+  PARALLEL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel"))) {
+    PARALLEL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the remote jobs and waiting for completion,
+  // delstar will simply list the remote command and wait for the user to signal completion
+  PARALLEL_MANUAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-manual"))) {
+    PARALLEL = TRUE; // -parallel-manual implies -parallel
+    PARALLEL_MANUAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the delstar_client jobs remotely, they are 
+  // run in serial via 'system'
+  PARALLEL_SERIAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-serial"))) {
+    if (PARALLEL_MANUAL) {
+      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
+      exit (1);
+    }
+    PARALLEL = TRUE; // -parallel-serial implies -parallel
+    PARALLEL_SERIAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  IMAGENAME = NULL;
+  MODE = MODE_NONE;
+  if ((N = get_argument (argc, argv, "-name"))) {
+    if (MODE != MODE_NONE) usage();
     MODE = MODE_IMAGENAME;
-    remove_argument (N, argc, argv);
-  }
-  if ((N = get_argument (*argc, argv, "-orphan"))) {
-    if (MODE != MODE_IMAGEFILE) usage();
+    remove_argument (N, &argc, argv);
+    IMAGENAME = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-file"))) {
+    if (MODE != MODE_NONE) usage();
+    MODE = MODE_IMAGENAME;
+    remove_argument (N, &argc, argv);
+    IMAGENAME = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-orphan"))) {
+    if (MODE != MODE_NONE) usage();
     MODE = MODE_ORPHAN;
-    remove_argument (N, argc, argv);
-  }
-  if ((N = get_argument (*argc, argv, "-missed"))) {
-    if (MODE != MODE_IMAGEFILE) usage();
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-missed"))) {
+    if (MODE != MODE_NONE) usage();
     MODE = MODE_MISSED;
-    remove_argument (N, argc, argv);
-  }
-  if ((N = get_argument (*argc, argv, "-time"))) {
-    if (MODE != MODE_IMAGEFILE) usage();
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-photcodes"))) {
+    if (MODE != MODE_NONE) usage();
+    MODE = MODE_PHOTCODES;
+    remove_argument (N, &argc, argv);
+    PHOTCODE_LIST = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-time"))) {
+    if (MODE != MODE_NONE) usage();
     MODE = MODE_TIME;
-    remove_argument (N, argc, argv);
+    remove_argument (N, &argc, argv);
 
     if (!ohana_str_to_time (argv[N], &START)) usage ();
-    remove_argument (N, argc, argv);
+    remove_argument (N, &argc, argv);
 
     /* interpret second value */
@@ -71,5 +138,5 @@
 	END = START + trange;
       }
-      remove_argument (N, argc, argv);
+      remove_argument (N, &argc, argv);
       goto goodtime;
     }
@@ -81,21 +148,88 @@
 	END   = tmp;
       }
-      remove_argument (N, argc, argv);
+      remove_argument (N, &argc, argv);
       goto goodtime;
     }
     usage ();
   }
+
 goodtime:
 
-  /* restrict to a single photcode (not compatible with -image) */
+  /* restrict to a single photcode (not compatible with -image) 
   PHOTCODE = NULL;
-  if ((N = get_argument (*argc, argv, "-photcode"))) {
-    remove_argument (N, argc, argv);
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    remove_argument (N, &argc, argv);
     PHOTCODE = GetPhotcodebyName (argv[N]);
-    remove_argument (N, argc, argv);
-  }
-
-  if ((MODE == MODE_TIME) && (*argc != 1)) usage ();
-  if ((MODE != MODE_TIME) && (*argc != 2)) usage ();
+    remove_argument (N, &argc, argv);
+  }*/
+
+  if (argc != 1) usage ();
   return (TRUE);
 }
+
+int args_client (int argc, char **argv) {
+  
+  int N;
+
+  // by definition, the client is not parallel 
+  PARALLEL = FALSE;
+  PARALLEL_MANUAL = FALSE;
+  PARALLEL_SERIAL = FALSE;
+
+  HOST_ID = 0;
+  if ((N = get_argument (argc, argv, "-hostID"))) {
+    remove_argument (N, &argc, argv);
+    HOST_ID = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!HOST_ID) delstar_client_usage();
+
+  HOSTDIR = NULL;
+  if ((N = get_argument (argc, argv, "-hostdir"))) {
+    remove_argument (N, &argc, argv);
+    HOSTDIR = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!HOSTDIR) delstar_client_usage();
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* specify portion of the sky */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (argc, argv, "-region"))) {
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  MODE = MODE_NONE;
+  if ((N = get_argument (argc, argv, "-photcodes"))) {
+    if (MODE != MODE_NONE) delstar_client_usage();
+    MODE = MODE_PHOTCODES;
+    remove_argument (N, &argc, argv);
+    PHOTCODE_LIST = strcreate(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (MODE == MODE_NONE) delstar_client_usage ();
+  return (TRUE);
+}
Index: /trunk/Ohana/src/delstar/src/delete_image_photcodes.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delete_image_photcodes.c	(revision 34749)
+++ /trunk/Ohana/src/delstar/src/delete_image_photcodes.c	(revision 34749)
@@ -0,0 +1,46 @@
+# include "delstar.h"
+
+int delete_image_photcodes (FITS_DB *db) {
+
+  off_t i, j;
+  off_t  Nimage;
+  Image *image;
+  Image *outimage;
+
+  // xxx where does this go?
+  int Nphotcodes = 0;
+  PhotCode **photcodes = ParsePhotcodeList (PHOTCODE_LIST, &Nphotcodes, FALSE);
+
+  image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
+
+  /* delete the identified images */
+  off_t Noutimage = 0;
+  ALLOCATE (outimage, Image, Nimage);
+  for (i = 0; i < Nimage; i++) {
+    int drop = FALSE;
+    for (j = 0; !drop && (j < Nphotcodes); j++) {
+      drop |= (photcodes[j][0].code == image[i].photcode);
+    }
+    if (drop) continue;
+    outimage[Noutimage] = image[i];
+    Noutimage ++;
+  }
+  free (image);
+  
+  if (VERBOSE) fprintf (stderr, "removing "OFF_T_FMT" images (leaving "OFF_T_FMT" of "OFF_T_FMT")\n",  Nimage - Noutimage, Noutimage, Nimage);
+  // gfits_table_set_Image (&db[0].ftable, outimage, Noutimage);
+
+  gfits_modify (&db[0].theader, "NAXIS2", OFF_T_FMT, 1,  Noutimage);
+  gfits_modify (&db[0].header, "NIMAGES", OFF_T_FMT, 1,  Noutimage);
+  db[0].theader.Naxis[1] = Noutimage;
+  db[0].ftable.buffer = (char *) outimage;
+
+  if (!dvo_image_save (db, VERBOSE)) return FALSE;
+  if (!dvo_image_unlock (db)) return FALSE;
+
+  return TRUE;
+}
Index: /trunk/Ohana/src/delstar/src/delete_imagefile.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delete_imagefile.c	(revision 34748)
+++ /trunk/Ohana/src/delstar/src/delete_imagefile.c	(revision 34749)
@@ -1,5 +1,5 @@
 # include "delstar.h"
 
-void delete_imagefile (FITS_DB *db, char *filename) {
+void delete_imagefile (FITS_DB *db) {
 
   off_t i, Nimlist;
@@ -16,5 +16,5 @@
 
   /* load information about file - time/photcode */
-  image = gimages (filename);
+  image = gimages (IMAGENAME);
   
   /* need to define method to get the mosaic (look up from table) */
@@ -54,5 +54,5 @@
   // XXX EAM : load image data above, find mosaic?
   imlist = find_images_data (db, image, &Nimlist);
-  if (!Nimlist) Shutdown ("image %s not found in db", filename);
+  if (!Nimlist) Shutdown ("image %s not found in db", IMAGENAME);
 
   gfits_vtable_from_ftable (&db[0].ftable, &db[0].vtable, imlist, Nimlist);
Index: /trunk/Ohana/src/delstar/src/delete_imagename.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delete_imagename.c	(revision 34748)
+++ /trunk/Ohana/src/delstar/src/delete_imagename.c	(revision 34749)
@@ -1,5 +1,5 @@
 # include "delstar.h"
 
-void delete_imagename (FITS_DB *db, char *name) {
+void delete_imagename (FITS_DB *db) {
 
   off_t i, j, k;
@@ -25,6 +25,6 @@
 
   /* find image in db by name */
-  imlist = find_images_name (db, name, &Nimlist);
-  if (!Nimlist) Shutdown ("image %s not found in db", name);
+  imlist = find_images_name (db, IMAGENAME, &Nimlist);
+  if (!Nimlist) Shutdown ("image %s not found in db", IMAGENAME);
   
   for (k = 0; k < Nimlist; k++) {
Index: /trunk/Ohana/src/delstar/src/delete_photcodes.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delete_photcodes.c	(revision 34749)
+++ /trunk/Ohana/src/delstar/src/delete_photcodes.c	(revision 34749)
@@ -0,0 +1,350 @@
+# include "delstar.h"
+
+int delete_photcodes (int hostID, char *hostpath) {
+
+  int i;
+  Catalog catalog;
+
+  // load the current sky table (layout of all SkyRegions) 
+  SkyTable *sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, TRUE, -1, VERBOSE);
+  if (!sky) {
+    fprintf (stderr, "ERROR running loading sky table from %s\n", CATDIR);
+    exit (2);
+  }
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+  if (!skylist) {
+    fprintf (stderr, "ERROR setting up skylist for %s\n", CATDIR);
+    exit (2);
+  }
+
+  // launch the remote jobs
+  if (PARALLEL && !hostID) {
+    int status = delete_photcodes_parallel (skylist);
+    return status;
+  }
+
+  // xxx where does this go?
+  int Nphotcodes = 0;
+  PhotCode **photcodes = ParsePhotcodeList (PHOTCODE_LIST, &Nphotcodes, FALSE);
+
+  // delete detections from region
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // does this host ID match the desired location for the table?
+    if (!HostTableTestHost(skylist[0].regions[i], hostID)) continue;
+
+    // set up the basic catalog info
+    char hostfile[1024];
+    snprintf (hostfile, 1024, "%s/%s.cpt", hostpath, skylist[0].regions[i]->name);
+    catalog.filename  = hostID ? hostfile : skylist[0].filename[i];
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+    if (VERBOSE) fprintf (stderr, "deleting from %s\n", catalog.filename);
+
+    // an error exit status here is a significant error
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "a")) {
+      fprintf (stderr, "ERROR: failure to open catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+    if (!catalog.Naves_disk) {
+      if (VERBOSE) fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    delete_photcodes_catalog (&catalog, photcodes, Nphotcodes);
+    dvo_catalog_save_complete (&catalog, VERBOSE);
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+  return TRUE;
+}
+
+// CATDIR is supplied globally
+# define DEBUG 1
+int delete_photcodes_parallel (SkyList *sky) {
+
+  // launch the delstar_client jobs to the parallel hosts
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
+  if (!table) {
+    fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", sky->hosts, CATDIR);
+    exit (1);
+  }    
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    // ensure that the paths are absolute path names
+    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
+    free (table->hosts[i].pathname);
+    table->hosts[i].pathname = tmppath;
+
+    // options / arguments that can affect relphot_client -update-objects:
+    // VERBOSE
+
+    char command[1024];
+    snprintf (command, 1024, "delstar_client -hostID %d -D CATDIR %s -hostdir %s -region %f %f %f %f -photcodes %s", 
+	      table->hosts[i].hostID, CATDIR, table->hosts[i].pathname, 
+	      UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax, 
+	      PHOTCODE_LIST);
+
+    char tmpline[1024];
+    if (VERBOSE)       { snprintf (tmpline, 1024, "%s -v",              command);                    strcpy (command, tmpline); }
+
+    fprintf (stderr, "command: %s\n", command);
+
+    if (PARALLEL_MANUAL) continue;
+
+    if (PARALLEL_SERIAL) {
+      int status = system (command);
+      if (status) {
+	fprintf (stderr, "ERROR running delstar_client\n");
+	exit (2);
+      }
+    } else {
+      // launch the job on the remote machine (no handshake)
+      int errorInfo = 0;
+      int pid = rconnect ("ssh", table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
+      if (!pid) {
+	if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
+	exit (1);
+      }
+      table->hosts[i].pid = pid; // save for future reference
+    }
+  }
+
+  if (PARALLEL_MANUAL) {
+    fprintf (stderr, "run the delstar_client commands above.  when these are done, hit return\n");
+    getchar();
+  }
+  if (!PARALLEL_MANUAL && !PARALLEL_SERIAL) {
+    HostTableWaitJobsGetIO (table, __FILE__, __LINE__, VERBOSE);
+  }
+
+  return TRUE;
+}      
+
+// sort the measure Sequence based on the average Sequence entries
+void SortAveMeasMatch (off_t *MEAS, off_t *AVE, off_t N) {
+
+# define SWAPFUNC(A,B){ off_t tmp_meas; off_t tmp_ave;	\
+    tmp_meas = MEAS[A]; MEAS[A] = MEAS[B]; MEAS[B] = tmp_meas;		\
+    tmp_ave  = AVE[A];  AVE[A]  = AVE[B];  AVE[B]  = tmp_ave;		\
+  }
+# define COMPARE(A,B)(AVE[A] < AVE[B])
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+# undef SWAPFUNC
+# undef COMPARE
+}
+
+int delete_photcodes_catalog (Catalog *catalog, PhotCode **photcodes, int Nphotcodes) {
+
+  off_t i, j, n, m, N, D, currentAve;
+
+  Measure *measureOut = NULL;
+  Average *averageOut = NULL;
+  SecFilt *secfiltOut = NULL;
+
+  off_t *measureDrop, *measureSeqRaw, *measureSeqOut, *measureRefOut, *measureAveRaw, *averageNmeas, *averageDmeas, *averageSeqOut, *averageRefOut, *measureAveOut;
+
+  int Nsecfilt = GetPhotcodeNsecfilt ();
+
+  /* internal counters */
+  off_t Nmeasure = catalog[0].Nmeasure;
+  off_t Naverage = catalog[0].Naverage;
+
+  Measure *measure = catalog[0].measure;
+  Average *average = catalog[0].average;
+  SecFilt *secfilt = catalog[0].secfilt;
+  
+  if (VERBOSE) fprintf (stderr, "starting with Nave, Nmeas: "OFF_T_FMT" "OFF_T_FMT"\n",  catalog[0].Naverage,  catalog[0].Nmeasure);
+
+  // we have a table of average objects and an unsorted table of measurements.  each measurement
+  // has a reference to the average object sequence (as well as an ID)
+  // measure[i].averef -> average[averef]
+  // measure[i].objID = average[averef].objID
+  // measure[i].catID = average[averef].catID
+
+  // we want a sorted measure array with all averef entries in sequence, skipping the entries which match our criteria
+
+  // arrays 
+  ALLOCATE (measureDrop,   off_t, Nmeasure);
+  ALLOCATE (measureSeqRaw, off_t, Nmeasure);
+  ALLOCATE (measureSeqOut, off_t, Nmeasure);
+  ALLOCATE (measureRefOut, off_t, Nmeasure);
+  ALLOCATE (measureAveRaw, off_t, Nmeasure);
+  ALLOCATE (averageNmeas,  off_t, Naverage);
+  ALLOCATE (averageDmeas,  off_t, Naverage);
+  ALLOCATE (averageSeqOut, off_t, Naverage);
+  ALLOCATE (averageRefOut, off_t, Naverage);
+
+  // mark the measures to be dropped
+  for (i = 0; i < Nmeasure; i++) {
+    int drop = FALSE;
+    for (j = 0; !drop && (j < Nphotcodes); j++) {
+      drop |= (photcodes[j][0].code == measure[i].photcode);
+    }
+    measureDrop[i] = drop;
+  }
+
+  // set up the measure sequence lists
+  for (i = 0; i < Nmeasure; i++) {
+    measureSeqRaw[i] = i;
+    measureAveRaw[i] = measure[i].averef;
+  }
+  // sort measureSeqRaw and measureAveRaw in order of measureAveRaw
+  SortAveMeasMatch(measureSeqRaw, measureAveRaw, Nmeasure);
+
+  // generate the measureSeqOut array
+  off_t NmeasOut = 0;
+  for (i = 0; i < Nmeasure; i++) {
+    j = measureSeqRaw[i];
+    if (measureDrop[j]) continue;
+    measureSeqOut[NmeasOut] = j;
+    measureRefOut[j] = NmeasOut;
+    NmeasOut ++;
+  }
+  // n = measureSeqOut[i] : measureOut[i] = measure[n]  (i = 0 -- NmeasOut, n = 0 -- Nmeasure)
+  // n = measureRefOut[i] : measureOut[n] = measure[i]
+  ALLOCATE (measureAveOut, off_t, NmeasOut);
+
+  // count the number of measures for each averef
+  N =  0;
+  D = -1;
+  currentAve = measureAveRaw[0];
+  for (i = 0; i < Nmeasure; i++) {
+    if (measureAveRaw[i] != currentAve) {
+      // we have hit the next entry in the list
+      averageNmeas[currentAve] = N; // number of measures
+      averageDmeas[currentAve] = D; // first measure 
+      N =  0;
+      D = -1;
+      currentAve = measureAveRaw[i];
+    }
+    j = measureSeqRaw[i];
+    if (measureDrop[j]) continue;
+    N++;
+    if (D == -1) { 
+      // first valid measureOut for this averef
+      D = measureRefOut[j];
+    }
+  }
+  averageNmeas[currentAve] = N; // number of measures
+  averageDmeas[currentAve] = D; // first measure 
+
+  // generate the new average sequence, skipping entries with no measurements
+  off_t NaveOut = 0;
+  for (i = 0; i < Naverage; i++) {
+    if (averageNmeas[i] == 0) continue;
+    averageSeqOut[NaveOut] = i;
+    averageRefOut[i] = NaveOut;
+    NaveOut ++;
+  }
+  // n = averageSeqOut[i] : averageOut[i] = average[n]  (i = 0 -- NaveOut, n = 0 -- Naverage)
+  // n = averageRefOut[i] : averageOut[n] = average[i]
+
+  // generate the output averefs
+  for (i = 0; i < NmeasOut; i++) {
+    j = measureSeqOut[i]; // measure[j] = measureOut[i]
+    n = measureAveRaw[j]; // average[n] : measure[j]
+    N = averageRefOut[n]; // averageOut[N] = average[n];
+    measureAveOut[i] = N; // measureOut[i].averef = measureAveOut[i] 
+  }
+
+  // copy the (kept) measurements in the sorted order
+  ALLOCATE (measureOut, Measure, NmeasOut);
+  for (i = 0; i < NmeasOut; i++) {
+    j = measureSeqOut[i];
+    measureOut[i] = measure[j];
+    measureOut[i].averef = measureAveOut[i];
+  }
+
+  // copy the (kept) average entries
+  ALLOCATE (averageOut, Average, NaveOut);
+  for (i = 0; i < NaveOut; i++) {
+    j = averageSeqOut[i];
+    averageOut[i] = average[j];
+    averageOut[i].Nmeasure      = averageNmeas[j]; 
+    averageOut[i].measureOffset = averageDmeas[j];
+  }
+
+  // copy the secfilt entries for the (kept) average entries
+  ALLOCATE (secfiltOut, SecFilt, NaveOut*Nsecfilt);
+  for (i = 0; i < NaveOut; i++) {
+    j = averageSeqOut[i];
+    for (m = 0; m < Nsecfilt; m++) {
+      secfiltOut[i*Nsecfilt + m] = secfilt[j*Nsecfilt + m];
+    }
+  }
+
+  // update the values of average.measureOffset and average.Nmeasure
+  FREE(measure);
+  FREE(average);
+  catalog[0].measure = measureOut;
+  catalog[0].average = averageOut;
+  catalog[0].secfilt = secfiltOut;
+  catalog[0].Nmeasure = NmeasOut;
+  catalog[0].Naverage = NaveOut;
+
+  // update catalog.Nmeasure and catalog.Naverage, double check 
+  int NmeasureTotal = 0;
+  int measureOffsetOK = TRUE;
+  int averefOK = TRUE;
+  for (i = 0; i < NaveOut; i++) {
+    NmeasureTotal += catalog[0].average[i].Nmeasure;
+    if (VERBOSE && !(NmeasureTotal <= catalog[0].Nmeasure)) {
+      fprintf (stderr, "too few measurements: %d %d %d\n", (int) i, NmeasureTotal, (int) catalog[0].Nmeasure);
+    }
+    measureOffsetOK &= (catalog[0].average[i].measureOffset < catalog[0].Nmeasure);
+    if (VERBOSE && !(catalog[0].average[i].measureOffset < catalog[0].Nmeasure)) {
+      fprintf (stderr, "offset too large: %d %d %d\n", (int) i, catalog[0].average[i].Nmeasure, (int) catalog[0].Nmeasure);
+    }
+    measureOffsetOK &= (catalog[0].average[i].measureOffset + catalog[0].average[i].Nmeasure <= catalog[0].Nmeasure);
+    if (VERBOSE && !(catalog[0].average[i].measureOffset + catalog[0].average[i].Nmeasure <= catalog[0].Nmeasure)) {
+      fprintf (stderr, "orrset + Nmeasure too large: %d + %d > %d %d\n", (int) i, catalog[0].average[i].measureOffset, catalog[0].average[i].Nmeasure, (int) catalog[0].Nmeasure);
+    }
+    m = catalog[0].average[i].measureOffset;
+    for (j = 0; j < catalog[0].average[i].Nmeasure; j++) {
+      averefOK &= (catalog[0].measure[m+j].averef == i);
+      if (VERBOSE && !(catalog[0].measure[m+j].averef == i)) {
+	fprintf (stderr, "averef broken: %d vs %d (measure %d)\n", (int) i, catalog[0].measure[m+j].averef, (int) (m+j));
+      }
+    }
+  }
+
+  if (!measureOffsetOK) {
+    fprintf (stderr, "ERROR: catalog %s has an invalid measureOffset\n", catalog[0].filename);
+  }
+
+  if (!averefOK) {
+    fprintf (stderr, "ERROR: catalog %s has invalid averefs\n", catalog[0].filename);
+  }
+
+  if (NmeasureTotal != catalog[0].Nmeasure) {
+    fprintf (stderr, "ERROR: catalog %s has an invalid Nmeasure\n", catalog[0].filename);
+  }
+
+  // MARKTIME("  match time %9.4f sec for %7lld measures, %6lld average\n", dtime, (long long) Nmeasure, (long long) Naverage);
+
+  catalog[0].sorted = TRUE;
+
+  if (VERBOSE) fprintf (stderr, "ending with Nave, Nmeas: "OFF_T_FMT" "OFF_T_FMT"\n",  catalog[0].Naverage,  catalog[0].Nmeasure);
+
+  FREE (measureDrop);
+  FREE (measureSeqRaw);
+  FREE (measureSeqOut);
+  FREE (measureAveRaw);
+  FREE (averageNmeas);
+  FREE (averageDmeas);
+  FREE (averageSeqOut);
+  FREE (averageRefOut);
+  FREE (measureAveOut);
+
+  return TRUE;
+}
Index: /trunk/Ohana/src/delstar/src/delstar.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delstar.c	(revision 34748)
+++ /trunk/Ohana/src/delstar/src/delstar.c	(revision 34749)
@@ -8,5 +8,5 @@
   SetSignals ();
   ConfigInit (&argc, argv);
-  args (&argc, argv);
+  args (argc, argv);
 
   set_db (&db);
@@ -20,12 +20,21 @@
   switch (MODE) {
     case MODE_IMAGEFILE:
-      delete_imagefile (&db, argv[1]);
+      delete_imagefile (&db);
       break;
     case MODE_IMAGENAME:
-      delete_imagename (&db, argv[1]);
+      delete_imagename (&db);
       break;
     case MODE_TIME:
       delete_times (&db);
       break;
+    case MODE_PHOTCODES: {
+      if (!delete_image_photcodes (&db)) exit (1);
+
+      if (!delete_photcodes (0, NULL)) {
+	fprintf (stderr, "failure deleting measurements\n");
+	exit (1);
+      }
+      exit (0);
+    }
     case MODE_ORPHAN:
       fprintf (stderr, "delete orphans not available\n");
Index: /trunk/Ohana/src/delstar/src/delstar_client.c
===================================================================
--- /trunk/Ohana/src/delstar/src/delstar_client.c	(revision 34749)
+++ /trunk/Ohana/src/delstar/src/delstar_client.c	(revision 34749)
@@ -0,0 +1,45 @@
+# include "delstar.h"
+
+// delstar_client is run on a remote host and is responsible for deleting measures from the
+// catalogs owned by that host.
+
+int main (int argc, char **argv) {
+
+  SetSignals ();
+  ConfigInit (&argc, argv);
+  args_client (argc, argv);
+
+  // load the current sky table (layout of all SkyRegions) 
+  SkyTable *sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, TRUE, -1, VERBOSE);
+  if (!sky) {
+      fprintf (stderr, "ERROR running loading sky table from %s\n", CATDIR);
+      exit (2);
+  }
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+  if (!skylist) {
+      fprintf (stderr, "ERROR setting up skylist for %s\n", CATDIR);
+      exit (2);
+  }
+
+  switch (MODE) {
+    case MODE_IMAGEFILE:
+      break;
+    case MODE_IMAGENAME:
+      break;
+    case MODE_TIME:
+      break;
+    case MODE_PHOTCODES:
+      delete_photcodes (HOST_ID, HOSTDIR);
+      break;
+    case MODE_ORPHAN:
+      break;
+    case MODE_MISSED:
+      break;
+    default:
+      usage ();
+  }
+  fprintf (stderr, "this mode is not supported by delstar_client\n");
+  exit (1);
+}
Index: /trunk/Ohana/src/getstar/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/getstar/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/getstar/src/ConfigInit.c	(revision 34749)
@@ -5,5 +5,4 @@
   char *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -21,5 +20,4 @@
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
   if (!ScanConfig (config, "SKY_DEPTH",         "%d",  0, &SKY_DEPTH)) {
     SKY_DEPTH = 2;
@@ -34,6 +32,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/kapa2/test/boxfont.sh
===================================================================
--- /trunk/Ohana/src/kapa2/test/boxfont.sh	(revision 34749)
+++ /trunk/Ohana/src/kapa2/test/boxfont.sh	(revision 34749)
@@ -0,0 +1,33 @@
+
+# make a plot with labels, ticks, and textlines 
+macro testplot
+
+  section a 0.0 0.0 0.5 0.5
+  box
+  label -fn times 18 -x xbar
+  textline -frac 0.3 0.3 foobar -fn times 12
+  textline -frac 0.1 0.1 "" -fn times 24 
+
+  section b 0.0 0.5 0.5 0.5
+  box
+  label -fn times 18 -x xbar
+  textline -frac 0.3 0.3 foobar -fn times 12
+  textline -frac 0.1 0.1 "" -fn times 24 
+
+  section c 0.5 0.0 0.5 0.5
+  box
+  label -fn times 18 -x xbar
+  textline -frac 0.3 0.3 foobar -fn times 12
+  textline -frac 0.1 0.1 "" -fn times 24 
+end
+
+# make a plot with labels, ticks, and textlines 
+macro testplot2
+
+  label -fn times 24
+  box
+  label -fn helvetica 18 -x xbar
+  textline -frac 0.3 0.3 foobar -fn courier 12
+  textline -frac 0.1 0.1 "" -fn times 24 
+end
+
Index: /trunk/Ohana/src/libautocode/def/measure-ps1-v4.d
===================================================================
--- /trunk/Ohana/src/libautocode/def/measure-ps1-v4.d	(revision 34748)
+++ /trunk/Ohana/src/libautocode/def/measure-ps1-v4.d	(revision 34749)
@@ -2,5 +2,5 @@
 EXTNAME      DVO_MEASURE_PS1_V4
 TYPE         BINTABLE
-SIZE         176
+SIZE         184
 DESCRIPTION  DVO Detection Measurement Table 
 
@@ -29,4 +29,7 @@
 FIELD Xccd,           X_CCD,        float,          X coord on chip,               pixels
 FIELD Yccd,           Y_CCD,        float,          Y coord on chip,               pixels
+
+FIELD Xoff,           X_OFF,        float,          X correction in chip coords,   pixels
+FIELD Yoff,           Y_OFF,        float,          Y correction in chip coords,   pixels
 
 # could these be packed into fewer bits?
Index: /trunk/Ohana/src/libautocode/def/measure.d
===================================================================
--- /trunk/Ohana/src/libautocode/def/measure.d	(revision 34748)
+++ /trunk/Ohana/src/libautocode/def/measure.d	(revision 34749)
@@ -2,5 +2,5 @@
 EXTNAME      DVO_MEASURE
 TYPE         BINTABLE
-SIZE         176
+SIZE         184
 DESCRIPTION  DVO Detection Measurement Table 
 
@@ -29,4 +29,7 @@
 FIELD Xccd,           X_CCD,        float,          X coord on chip,                pixels
 FIELD Yccd,           Y_CCD,        float,          Y coord on chip,                pixels
+
+FIELD Xoff,           X_OFF,        float,          X correction in chip coords,   pixels
+FIELD Yoff,           Y_OFF,        float,          Y correction in chip coords,   pixels
 
 # could these be packed into fewer bits?
Index: /trunk/Ohana/src/libdvo/doc/notes.txt
===================================================================
--- /trunk/Ohana/src/libdvo/doc/notes.txt	(revision 34748)
+++ /trunk/Ohana/src/libdvo/doc/notes.txt	(revision 34749)
@@ -17,5 +17,5 @@
 
 4) create a DVOTableFormat entry for the new format
-   (libdvo/include/dvo.h).  the naming convetion is DVO_FORMAT_FOO.
+   (libdvo/include/dvo.h).  the naming convention is DVO_FORMAT_FOO.
 
 5) add an entry for the new format in dvo_catalog_catformat
Index: /trunk/Ohana/src/libdvo/include/dvo.h
===================================================================
--- /trunk/Ohana/src/libdvo/include/dvo.h	(revision 34748)
+++ /trunk/Ohana/src/libdvo/include/dvo.h	(revision 34749)
@@ -175,4 +175,7 @@
   ID_OBJ_GOOD       = 0x04000000, // good-quality measurement in our data (eg,PS)
   ID_OBJ_GOOD_ALT   = 0x08000000, // good-quality measurement in  external data (eg, 2MASS)
+  ID_OBJ_GOOD_STACK = 0x10000000, // good-quality object in the stack (> 1 good stack)
+  ID_OBJ_SUSPECT_STACK = 0x20000000, // suspect object in the stack (> 1 good or suspect stack, < 2 good)
+  ID_OBJ_BAD_STACK  = 0x40000000, // good-quality object in the stack (> 1 good stack)
 } DVOAverageFlags;
 
Index: /trunk/Ohana/src/libdvo/include/dvodb.h
===================================================================
--- /trunk/Ohana/src/libdvo/include/dvodb.h	(revision 34748)
+++ /trunk/Ohana/src/libdvo/include/dvodb.h	(revision 34749)
@@ -122,4 +122,6 @@
       MEAS_XCCD_ERR, 
       MEAS_YCCD_ERR, 
+      MEAS_XOFF, 
+      MEAS_YOFF, 
       MEAS_POS_SYS_ERR, 
       MEAS_XMOSAIC, 
Index: /trunk/Ohana/src/libdvo/src/LoadPhotcodes.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/LoadPhotcodes.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/LoadPhotcodes.c	(revision 34749)
@@ -11,4 +11,6 @@
   }
 
+  if (!master_file) return FALSE;
+
   /* next try to load the photcodes from the master text photcode file */
   /* automatically (or on demand?) save the text file to the FITS version */
Index: /trunk/Ohana/src/libdvo/src/dbExtractMeasures.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 34749)
@@ -385,4 +385,12 @@
       value.Flt = FromShortDegrees(measure[0].theta);
       break;
+
+    case MEAS_POSANGLE: /* OK */
+      value.Flt = FromShortDegrees(measure[0].posangle);
+      break;
+    case MEAS_PLATESCALE: /* OK */
+      value.Flt = measure[0].pltscale;
+      break;
+
     case MEAS_MXX: /* OK */
       value.Flt = FromShortPixels(measure[0].Mxx);
@@ -435,4 +443,10 @@
 # endif
       break;
+    case MEAS_XOFF: /* OK */
+      value.Flt = measure[0].Xoff;
+      break;
+    case MEAS_YOFF: /* OK */
+      value.Flt = measure[0].Yoff;
+      break;
     case MEAS_XCCD_ERR: /* OK */
       value.Flt = FromShortPixels(measure[0].dXccd);
Index: /trunk/Ohana/src/libdvo/src/dbFields.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dbFields.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dbFields.c	(revision 34749)
@@ -217,4 +217,6 @@
   if (!strcasecmp (fieldName, "XCCD:ERR"))   	 ESCAPE (MEAS_XCCD_ERR,       MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "YCCD:ERR"))   	 ESCAPE (MEAS_YCCD_ERR,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "XOFF"))       	 ESCAPE (MEAS_XOFF,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YOFF"))       	 ESCAPE (MEAS_YOFF,           MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "POS_SYS_ERR"))    ESCAPE (MEAS_POS_SYS_ERR,    MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "XMOSAIC"))    	 ESCAPE (MEAS_XMOSAIC,        MAG_NONE, OPIHI_FLT);
@@ -228,4 +230,5 @@
   if (!strcasecmp (fieldName, "CATID"))      	 ESCAPE (MEAS_CAT_ID,         MAG_NONE, OPIHI_INT);
   if (!strcasecmp (fieldName, "IMAGEID"))    	 ESCAPE (MEAS_IMAGE_ID,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "EXTERNID"))    	 ESCAPE (MEAS_EXTERN_ID,      MAG_NONE, OPIHI_INT);
   if (!strcasecmp (fieldName, "PSF_QF"))     	 ESCAPE (MEAS_PSF_QF,         MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "PSF_QF_PERFECT")) ESCAPE (MEAS_PSF_QF_PERFECT, MAG_NONE, OPIHI_FLT);
@@ -237,5 +240,4 @@
   if (!strcasecmp (fieldName, "SKY"))        	 ESCAPE (MEAS_SKY,            MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "SKY_ERR"))    	 ESCAPE (MEAS_dSKY,           MAG_NONE, OPIHI_FLT);
-  if (!strcasecmp (fieldName, "externID"))    	 ESCAPE (MEAS_EXTERN_ID,      MAG_NONE, OPIHI_INT);
   if (!strcasecmp (fieldName, "MCAL_OFFSET"))    ESCAPE (MEAS_MCAL_OFFSET,    MAG_NONE, OPIHI_FLT);
   if (!strcasecmp (fieldName, "FLAT"))    	 ESCAPE (MEAS_FLAT,           MAG_NONE, OPIHI_FLT);
Index: /trunk/Ohana/src/libdvo/src/dvo_catalog.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_catalog.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_catalog.c	(revision 34749)
@@ -83,12 +83,12 @@
   average->dP        	   = 0;
 
-  average->ChiSqAve  	   = 0.0;
-  average->ChiSqPM   	   = 0.0;
-  average->ChiSqPar  	   = 0.0;
+  average->ChiSqAve  	   = NAN;
+  average->ChiSqPM   	   = NAN;
+  average->ChiSqPar  	   = NAN;
   average->Tmean   	   = 0;
   average->Trange   	   = 0;
 
-  average->psfQF   	   = 0.0;
-  average->psfQFperf   	   = 0.0;
+  average->psfQF   	   = NAN;
+  average->psfQFperf   	   = NAN;
 
   average->stargal    	   = 0.0;
@@ -161,4 +161,6 @@
  measure->Xccd      = NAN;
  measure->Yccd      = NAN;
+ measure->Xoff      = 0.0;
+ measure->Yoff      = 0.0;
 
  measure->Sky       = NAN;
@@ -176,4 +178,5 @@
 
  measure->psfQF     = NAN;
+ measure->psfQFperf = NAN;
  measure->psfChisq  = NAN;
  measure->psfNdof   = 0;
Index: /trunk/Ohana/src/libdvo/src/dvo_catalog_split.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 34749)
@@ -83,4 +83,5 @@
     return (FALSE);
   }
+  off_t fullsize = catalog->header.datasize;
 
   // write the PHU matrix; this is probably a NOP, do I have to keep it in?
@@ -91,4 +92,5 @@
     return (FALSE);
   }
+  fullsize += matrix.datasize;
   gfits_free_matrix (&matrix);
 
@@ -98,4 +100,15 @@
     return (FALSE);
   }
+  fullsize += ftable->datasize + ftable->header->datasize;
+
+  // if the output file will be completely re-written, truncate to total datasize
+  if ((start == 0) && (Nrows == Ntotal)) {
+    int fd = fileno (catalog->f);
+    if (ftruncate (fd, fullsize)) {
+      perror ("dvo_catalog_save_subset: ");
+      return (FALSE);
+    }
+  }
+
   return (TRUE);
 }
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_1.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_1.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_1.c	(revision 34749)
@@ -11,4 +11,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -40,30 +41,9 @@
     out[i].photFlags  = in[i].photFlags;
 
-    // changed or added for PS1_DEV_2
+    // changed for PS1_DEV_2
     out[i].Map        = in[i].Mgal;
-    out[i].dMcal      = 0; 
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].photFlags  = in[i].photFlags | (in[i].dophot << 16);
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -125,4 +105,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -138,30 +120,14 @@
     out[i].catID 	 = in[i].catID;
 
-    // changed or added for PS1_DEV_2
+    // changed for PS1_DEV_2
     out[i].Nmeasure      = in[i].Nm;     
     out[i].Nmissing      = in[i].Nn;     
     out[i].measureOffset = in[i].offset; 
     out[i].missingOffset = in[i].missing;
-    out[i].Nextend       = 0;
-    out[i].extendOffset  = 0;
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
+
+    // PS1_V4 : Xp dropped in V4 onward, was not really used anyway
   }
   return (out);
@@ -210,4 +176,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -215,25 +183,4 @@
     out[i].Ncode = in[i].Ncode;
     out[i].Nused = in[i].Nused;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_2.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_2.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_DEV_2.c	(revision 34749)
@@ -11,4 +11,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -41,26 +42,6 @@
     out[i].dbFlags    = in[i].dbFlags;
 
-    // changed or added for PS1_V1
+    // changed for PS1_V1
     out[i].photFlags  = in[i].photFlags | (in[i].dophot << 16);
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
  }
   return (out);
@@ -121,4 +102,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -140,22 +123,6 @@
     out[i].catID 	 = in[i].catID;
 
-    // changed or added for PS1_V1
+    // changed for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -204,4 +171,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -209,25 +178,4 @@
     out[i].Ncode = in[i].Ncode;
     out[i].Nused = in[i].Nused;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_REF.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_REF.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_REF.c	(revision 34749)
@@ -11,54 +11,17 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
+
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
     out[i].M          = in[i].M;
-    out[i].Mcal       = 0.0;
-    out[i].Map        = NAN;
     out[i].dM         = in[i].dM;
-    out[i].dMcal      = 0.0;
     out[i].dt         = in[i].dt;
-    out[i].airmass    = NAN;
-    out[i].az         = NAN;
-    out[i].Xccd       = NAN;
-    out[i].Yccd       = NAN;
-    out[i].Sky        = NAN;
-    out[i].dSky       = NAN;
     out[i].t          = in[i].t;
-    out[i].t_msec     = 0;
     out[i].averef     = in[i].averef;
-    out[i].detID      = 0;
-    out[i].imageID    = 0;
     out[i].objID      = in[i].objID;
     out[i].catID      = in[i].catID;
-    out[i].extID      = 0;
     out[i].psfQF      = 1.0; // we do not save a value, but some operations (relphot/average) filter on this value..
-    out[i].psfChisq   = NAN;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-    out[i].crNsigma   = NAN;
-    out[i].extNsigma  = NAN;
-    out[i].FWx 	      = 0;
-    out[i].FWy 	      = 0;
-    out[i].theta      = 0;
-    out[i].Mxx 	      = 0;
-    out[i].Mxy 	      = 0;
-    out[i].Myy 	      = 0;
-    out[i].dXccd      = 0;
-    out[i].dYccd      = 0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = NAN;
     out[i].photcode   = in[i].photcode;
-    out[i].dbFlags    = 0;
-    out[i].photFlags  = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -96,39 +59,16 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
     out[i].dR       	 = in[i].dR;
     out[i].dD       	 = in[i].dD;
-    out[i].uR       	 = NAN;
-    out[i].uD       	 = NAN;
-    out[i].duR      	 = NAN;
-    out[i].duD      	 = NAN;
-    out[i].P        	 = NAN;
-    out[i].dP       	 = NAN;
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0;
     out[i].Nmeasure      = in[i].Nmeasure;     
     out[i].Nmissing      = in[i].Nmissing;     
-    out[i].Nextend       = 0;
     out[i].measureOffset = in[i].measureOffset; 
     out[i].missingOffset = in[i].missingOffset;
-    out[i].extendOffset  = 0;
-    out[i].flags     	 = 0;
     out[i].objID 	 = in[i].objID;
     out[i].catID 	 = in[i].catID;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -167,28 +107,8 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
-    out[i].Xm    = NAN_S_SHORT;
-    out[i].Ncode = 0;
-    out[i].Nused = 0;
-    out[i].M_20  = 0;
-    out[i].M_80  = 0;
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V1.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V1.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V1.c	(revision 34749)
@@ -11,4 +11,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
+
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -52,13 +54,4 @@
     out[i].dbFlags    = in[i].dbFlags;
     out[i].photFlags  = in[i].photFlags;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -128,4 +121,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -139,8 +134,4 @@
     out[i].dP       	 = in[i].dP;
     out[i].ChiSqAve    	 = in[i].ChiSq;     
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange    	 = 0;
     out[i].Npos       	 = in[i].Npos;     
     out[i].Nmeasure      = in[i].Nmeasure;     
@@ -154,13 +145,4 @@
     out[i].catID 	 = in[i].catID;
     out[i].extID 	 = in[i].extID;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -210,4 +192,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -217,21 +201,4 @@
     out[i].M_20  = in[i].M_20;      
     out[i].M_80  = in[i].M_80;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V2.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V2.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V2.c	(revision 34749)
@@ -11,4 +11,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
+
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -53,13 +55,4 @@
     out[i].dbFlags    = in[i].dbFlags;
     out[i].photFlags  = in[i].photFlags;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -129,4 +122,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -155,13 +150,4 @@
     out[i].catID 	 = in[i].catID;
     out[i].extID 	 = in[i].extID;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -215,4 +201,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -223,18 +211,4 @@
     out[i].M_20  = in[i].M_20;      
     out[i].M_80  = in[i].M_80;      
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V3.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V3.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V3.c	(revision 34749)
@@ -11,4 +11,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
+
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -53,13 +55,4 @@
     out[i].dbFlags    = in[i].dbFlags;
     out[i].photFlags  = in[i].photFlags;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -129,4 +122,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -157,9 +152,4 @@
     out[i].catID 	 = in[i].catID;
     out[i].extID 	 = in[i].extID;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -215,4 +205,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M           = in[i].M;      
     out[i].Map         = in[i].Map;      
@@ -226,13 +218,4 @@
     out[i].Mstdev      = in[i].Mstdev;      
     out[i].ubercalDist = in[i].ubercalDist;      
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V4.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V4.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V4.c	(revision 34749)
@@ -9,4 +9,69 @@
 
   ALLOCATE_ZERO (out, Measure, Nvalues);
+
+  for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
+
+    out[i].dR         = in[i].dR;
+    out[i].dD         = in[i].dD;
+    out[i].M          = in[i].M;
+    out[i].Mcal       = in[i].Mcal;
+    out[i].Map        = in[i].Map;
+    out[i].Mkron      = in[i].Mkron;
+    out[i].dMkron     = in[i].dMkron;
+    out[i].dM         = in[i].dM;
+    out[i].dMcal      = in[i].dMcal;
+    out[i].dt         = in[i].dt;
+    out[i].FluxPSF    = in[i].FluxPSF;
+    out[i].dFluxPSF   = in[i].dFluxPSF;
+    out[i].FluxKron   = in[i].FluxKron;
+    out[i].dFluxKron  = in[i].dFluxKron;
+    out[i].airmass    = in[i].airmass;
+    out[i].az         = in[i].az;
+    out[i].Xccd       = in[i].Xccd;
+    out[i].Yccd       = in[i].Yccd;
+    out[i].Xoff       = in[i].Xoff;
+    out[i].Yoff       = in[i].Yoff;
+    out[i].Sky        = in[i].Sky;
+    out[i].dSky       = in[i].dSky;
+    out[i].t          = in[i].t;
+    out[i].t_msec     = in[i].t_msec;
+    out[i].averef     = in[i].averef;
+    out[i].detID      = in[i].detID;
+    out[i].imageID    = in[i].imageID;
+    out[i].objID      = in[i].objID;
+    out[i].catID      = in[i].catID;
+    out[i].extID      = in[i].extID;
+    out[i].psfQF      = in[i].psfQF;
+    out[i].psfQFperf  = in[i].psfQFperf;
+    out[i].psfChisq   = in[i].psfChisq;
+    out[i].psfNdof    = in[i].psfNdof;
+    out[i].psfNpix    = in[i].psfNpix;
+    out[i].crNsigma   = in[i].crNsigma;
+    out[i].extNsigma  = in[i].extNsigma;
+    out[i].FWx 	      = in[i].FWx;
+    out[i].FWy 	      = in[i].FWy;
+    out[i].theta      = in[i].theta;
+    out[i].Mxx 	      = in[i].Mxx;
+    out[i].Mxy 	      = in[i].Mxy;
+    out[i].Myy 	      = in[i].Myy;
+    out[i].dXccd      = in[i].dXccd;
+    out[i].dYccd      = in[i].dYccd;
+    out[i].dRsys      = in[i].dRsys;
+    out[i].posangle   = in[i].posangle;
+    out[i].pltscale   = in[i].pltscale;
+    out[i].photcode   = in[i].photcode;
+    out[i].dbFlags    = in[i].dbFlags;
+    out[i].photFlags  = in[i].photFlags;
+  }
+  return (out);
+}
+
+Measure_PS1_V4 *MeasureInternalTo_PS1_V4 (Measure *in, off_t Nvalues) {
+
+  off_t i;
+  Measure_PS1_V4 *out;
+
+  ALLOCATE_ZERO (out, Measure_PS1_V4, Nvalues);
 
   for (i = 0; i < Nvalues; i++) {
@@ -64,65 +129,4 @@
 }
 
-Measure_PS1_V4 *MeasureInternalTo_PS1_V4 (Measure *in, off_t Nvalues) {
-
-  off_t i;
-  Measure_PS1_V4 *out;
-
-  ALLOCATE_ZERO (out, Measure_PS1_V4, Nvalues);
-
-  for (i = 0; i < Nvalues; i++) {
-    out[i].dR         = in[i].dR;
-    out[i].dD         = in[i].dD;
-    out[i].M          = in[i].M;
-    out[i].Mcal       = in[i].Mcal;
-    out[i].Map        = in[i].Map;
-    out[i].Mkron      = in[i].Mkron;
-    out[i].dMkron     = in[i].dMkron;
-    out[i].dM         = in[i].dM;
-    out[i].dMcal      = in[i].dMcal;
-    out[i].dt         = in[i].dt;
-    out[i].FluxPSF    = in[i].FluxPSF;
-    out[i].dFluxPSF   = in[i].dFluxPSF;
-    out[i].FluxKron   = in[i].FluxKron;
-    out[i].dFluxKron  = in[i].dFluxKron;
-    out[i].airmass    = in[i].airmass;
-    out[i].az         = in[i].az;
-    out[i].Xccd       = in[i].Xccd;
-    out[i].Yccd       = in[i].Yccd;
-    out[i].Sky        = in[i].Sky;
-    out[i].dSky       = in[i].dSky;
-    out[i].t          = in[i].t;
-    out[i].t_msec     = in[i].t_msec;
-    out[i].averef     = in[i].averef;
-    out[i].detID      = in[i].detID;
-    out[i].imageID    = in[i].imageID;
-    out[i].objID      = in[i].objID;
-    out[i].catID      = in[i].catID;
-    out[i].extID      = in[i].extID;
-    out[i].psfQF      = in[i].psfQF;
-    out[i].psfQFperf  = in[i].psfQFperf;
-    out[i].psfChisq   = in[i].psfChisq;
-    out[i].psfNdof    = in[i].psfNdof;
-    out[i].psfNpix    = in[i].psfNpix;
-    out[i].crNsigma   = in[i].crNsigma;
-    out[i].extNsigma  = in[i].extNsigma;
-    out[i].FWx 	      = in[i].FWx;
-    out[i].FWy 	      = in[i].FWy;
-    out[i].theta      = in[i].theta;
-    out[i].Mxx 	      = in[i].Mxx;
-    out[i].Mxy 	      = in[i].Mxy;
-    out[i].Myy 	      = in[i].Myy;
-    out[i].dXccd      = in[i].dXccd;
-    out[i].dYccd      = in[i].dYccd;
-    out[i].dRsys      = in[i].dRsys;
-    out[i].posangle   = in[i].posangle;
-    out[i].pltscale   = in[i].pltscale;
-    out[i].photcode   = in[i].photcode;
-    out[i].dbFlags    = in[i].dbFlags;
-    out[i].photFlags  = in[i].photFlags;
-  }
-  return (out);
-}
-
 // 'primary' is needed to conform with the API for Loneos and Elixir, but is not used
 Average *Average_PS1_V4_ToInternal (Average_PS1_V4 *in, off_t Nvalues, SecFilt **primary) {
@@ -134,4 +138,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -221,4 +227,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M             = in[i].M;      
     out[i].Map           = in[i].Map;      
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_elixir.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_elixir.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_elixir.c	(revision 34749)
@@ -10,4 +10,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].FWx 	    = in[i].FWx;
     out[i].t        = in[i].t;
@@ -28,49 +29,17 @@
     
     // added for PANSTARRS_DEV_0
-    out[i].Xccd      = 0;  // determine on-the-fly
-    out[i].Yccd      = 0;  // determine on-the-fly
-    out[i].dXccd     = 0;
-    out[i].dYccd     = 0;
-    out[i].az        = 0;
-    out[i].Sky       = 0;
-    out[i].dSky      = 0;
-    out[i].psfQF     = 0;
-    out[i].psfChisq  = 0;
-    out[i].crNsigma  = 0;
-    out[i].extNsigma = 0;
-    out[i].detID     = 0;  // determine on-the-fly
-    out[i].imageID   = 0;  // determine on-the-fly
-
-    // changed or added for PS1_DEV_1 (2008.02.26)
+    // out[i].Xccd      = 0;  // determine on-the-fly
+    // out[i].Yccd      = 0;  // determine on-the-fly
+    // out[i].detID     = 0;  // determine on-the-fly
+    // out[i].imageID   = 0;  // determine on-the-fly
+
+    // changed for PS1_DEV_1 (2008.02.26)
     out[i].dbFlags    = in[i].flags;
-    out[i].detID      = 0;
-    out[i].imageID    = 0;
-
-    // changed or added for PS1_DEV_2
+
+    // changed for PS1_DEV_2
     out[i].Map        = in[i].Mgal;
-    out[i].dMcal      = 0; 
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].photFlags  = in[i].dophot << 16;
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -126,4 +95,7 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+    dvo_secfilt_init (&primary[0][i]);
+
     out[i].R       	 = in[i].R;      
     out[i].D       	 = in[i].D;      
@@ -134,18 +106,7 @@
     primary[0][i].Xm    = in[i].Xm;     
 
-    primary[0][i].Ncode = 0;     
-    primary[0][i].Nused = 0;
-
     // added for PANSTARRS_DEV_0
-    out[i].dR      = 0;
-    out[i].dD      = 0;
-    out[i].uR      = 0;
-    out[i].uD      = 0;
-    out[i].duR     = 0;
-    out[i].duD     = 0;
-    out[i].P       = 0;
-    out[i].dP      = 0;
-    out[i].objID   = 0; // determine on-the-fly
-    out[i].catID   = 0; // determine on-the-fly
+    // out[i].objID   = 0; // determine on-the-fly
+    // out[i].catID   = 0; // determine on-the-fly
 
     // changed or added for PS1_DEV_2
@@ -154,25 +115,7 @@
     out[i].measureOffset = in[i].offset; 
     out[i].missingOffset = in[i].missing;
-    out[i].Nextend       = 0;
-    out[i].extendOffset  = 0;
 
     // changed or added for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -217,4 +160,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].Xm    = in[i].Xm;     
 
@@ -222,27 +167,4 @@
     out[i].M     = (in[i].M  == NAN_S_SHORT) ? NAN : in[i].M   * 0.001;
     out[i].dM    = (in[i].dM == NAN_S_SHORT) ? NAN : in[i].dM  * 0.001;
-    out[i].Ncode = 0;
-    out[i].Nused = 0;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].stackDetectID     = 0;
   }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_loneos.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_loneos.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_loneos.c	(revision 34749)
@@ -10,4 +10,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].t        = in[i].t;
 
@@ -16,9 +17,4 @@
     out[i].dbFlags   = (in[i].averef & 0xff000000) >> 24;
     out[i].t         = in[i].t;
-    out[i].dt        = 0;
-    out[i].airmass   = 0;
-    out[i].FWy 	     = 0;
-    out[i].FWx       = 0;
-    out[i].theta     = 0;
 
     // changed for PANSTARRS_DEV_0
@@ -32,47 +28,11 @@
     
     // added for PANSTARRS_DEV_0
-    out[i].Xccd      = 0;  // determine on-the-fly
-    out[i].Yccd      = 0;  // determine on-the-fly
-    out[i].dXccd     = 0;
-    out[i].dYccd     = 0;
-    out[i].az        = 0;
-    out[i].Sky       = 0;
-    out[i].dSky      = 0;
-    out[i].psfQF     = 0;
-    out[i].psfChisq  = 0;
-    out[i].crNsigma  = 0;
-    out[i].extNsigma = 0;
-    out[i].detID     = 0;  // determine on-the-fly
-    out[i].imageID   = 0;  // determine on-the-fly
-
-    // changed or added for PS1_DEV_1 (2008.02.26)
-    out[i].detID      = 0;
-    out[i].imageID    = 0;
-
-    // changed or added for PS1_DEV_2
-    out[i].dMcal      = 0; 
+    // out[i].Xccd      = 0;  // determine on-the-fly
+    // out[i].Yccd      = 0;  // determine on-the-fly
+    // out[i].detID     = 0;  // determine on-the-fly
+    // out[i].imageID   = 0;  // determine on-the-fly
 
     // changed or added for PS1_V1
     out[i].photFlags  = in[i].dophot << 16;
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -117,27 +77,17 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+    dvo_secfilt_init (&primary[0][i]);
+
     out[i].R       	 = in[i].R;      
     out[i].D       	 = in[i].D;      
-
-    // added for ELIXIR
-    primary[0][i].dM    = NAN;
 
     // changed for PANSTARRS_DEV_0 (moved from Average to Measure)
     primary[0][i].M     = (in[i].M  == NAN_S_SHORT) ? NAN : in[i].M  * 0.001;      
     primary[0][i].Xm    = in[i].Xm;     
-    primary[0][i].Ncode = 0;     
-    primary[0][i].Nused = 0;
 
     // added for PANSTARRS_DEV_0
-    out[i].dR      = 0;
-    out[i].dD      = 0;
-    out[i].uR      = 0;
-    out[i].uD      = 0;
-    out[i].duR     = 0;
-    out[i].duD     = 0;
-    out[i].P       = 0;
-    out[i].dP      = 0;
-    out[i].objID   = 0; // determine on-the-fly
-    out[i].catID   = 0; // determine on-the-fly
+    // out[i].objID   = 0; // determine on-the-fly
+    // out[i].catID   = 0; // determine on-the-fly
 
     // changed or added for PS1_DEV_2
@@ -146,25 +96,9 @@
     out[i].measureOffset = in[i].offset; 
     out[i].missingOffset = in[i].missing;
-    out[i].Nextend       = 0;
-    out[i].extendOffset  = 0;
 
     // changed or added for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
+
+    // PS1_V4 : (Xp dropped in V4 onward, was not really used anyway)
   }
   return (out);
@@ -208,34 +142,10 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].Xm    = in[i].Xm;      
 
-    // added for ELIXIR
-    out[i].dM    = NAN;
-
     // added or changed for PANSTARRS_DEV_0
     out[i].M     = (in[i].M  == NAN_S_SHORT) ? NAN : in[i].M * 0.001;
-    out[i].Ncode = 0;
-    out[i].Nused = 0;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].stackDetectID     = 0;
   }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_0.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_0.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_0.c	(revision 34749)
@@ -10,4 +10,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -35,39 +36,15 @@
     // magnitudes.  Most uses of Mgal in the past were actually aperture (isophotal) mags
 
-    // changed or added for PS1_DEV_1 (2008.02.26)
+    // changed for PS1_DEV_1 (2008.02.26)
     out[i].psfQF      = (in[i].psfQF == NAN_S_SHORT) ? NAN : in[i].psfQF;
     out[i].dbFlags    = in[i].flags;
     out[i].detID      = in[i].detID_lo;
     out[i].imageID    = in[i].imageID_lo;
-    out[i].psfChisq   = 0;
-    out[i].crNsigma   = 0;
-    out[i].extNsigma  = 0;
-
-    // changed or added for PS1_DEV_2
+
+    // changed for PS1_DEV_2
     out[i].Map        = in[i].Mgal;
-    out[i].dMcal      = 0; 
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].photFlags  = in[i].dophot << 16;
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -132,4 +109,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -145,30 +124,12 @@
     out[i].catID 	 = in[i].catID;
 
-    // changed or added for PS1_DEV_2
+    // changed for PS1_DEV_2
     out[i].Nmeasure      = in[i].Nm;     
     out[i].Nmissing      = in[i].Nn;     
     out[i].measureOffset = in[i].offset; 
     out[i].missingOffset = in[i].missing;
-    out[i].Nextend       = 0;
-    out[i].extendOffset  = 0;
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange   	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -219,4 +180,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -224,25 +187,4 @@
     out[i].Ncode = in[i].Ncode;
     out[i].Nused = in[i].Nused;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_1.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_1.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/dvo_convert_panstarrs_DEV_1.c	(revision 34749)
@@ -10,4 +10,5 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_measure_init (&out[i]);
     out[i].dR         = in[i].dR;
     out[i].dD         = in[i].dD;
@@ -40,34 +41,10 @@
     out[i].detID      = in[i].detID_lo;
     out[i].imageID    = in[i].imageID_lo;
-    out[i].psfChisq   = 0;
-    out[i].crNsigma   = 0;
-    out[i].extNsigma  = 0;
-
-    // changed or added for PS1_DEV_2
+
+    // changed for PS1_DEV_2
     out[i].Map        = in[i].Mgal;
-    out[i].dMcal      = 0; 
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].photFlags  = in[i].dophot << 16;
-    out[i].t_msec     = 0;
-    out[i].extID      = 0;
-    out[i].objID      = 0;
-    out[i].catID      = 0;
-    out[i].Mxx 	      = 0.0;
-    out[i].Mxy 	      = 0.0;
-    out[i].Myy        = 0.0;
-    out[i].posangle   = 0;
-    out[i].pltscale   = 0;
-    out[i].psfNdof    = 0;
-    out[i].psfNpix    = 0;
-
-    // added for PS1_V4
-    out[i].Mkron      = NAN;
-    out[i].dMkron     = NAN;
-    out[i].FluxPSF    = NAN;
-    out[i].dFluxPSF   = NAN;
-    out[i].FluxKron   = NAN;
-    out[i].dFluxKron  = NAN;
-    out[i].psfQFperf  = NAN;
   }
   return (out);
@@ -132,4 +109,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_average_init (&out[i]);
+
     out[i].R        	 = in[i].R;      
     out[i].D        	 = in[i].D;      
@@ -145,30 +124,12 @@
     out[i].catID 	 = in[i].catID;
 
-    // changed or added for PS1_DEV_2
+    // changed for PS1_DEV_2
     out[i].Nmeasure      = in[i].Nm;     
     out[i].Nmissing      = in[i].Nn;     
     out[i].measureOffset = in[i].offset; 
     out[i].missingOffset = in[i].missing;
-    out[i].Nextend       = 0;
-    out[i].extendOffset  = 0;
-
-    // changed or added for PS1_V1
+
+    // changed for PS1_V1
     out[i].flags    	 = in[i].code;   
-    out[i].ChiSqAve    	 = NAN;
-    out[i].ChiSqPM    	 = NAN;
-    out[i].ChiSqPar    	 = NAN;
-    out[i].Tmean    	 = 0;
-    out[i].Trange    	 = 0;
-    out[i].Npos       	 = 0.0;
-    out[i].extID 	 = 0;
-
-    // added in PS1_V3
-    out[i].photFlagsUpper = 0;
-    out[i].photFlagsLower = 0;
-
-    // added for PS1_V4 (Xp dropped in V4 onward, was not really used anyway)
-    out[i].psfQF         = NAN;
-    out[i].psfQFperf     = NAN;
-    out[i].stargal     	 = NAN;
   }
   return (out);
@@ -219,4 +180,6 @@
 
   for (i = 0; i < Nvalues; i++) {
+    dvo_secfilt_init (&out[i]);
+
     out[i].M     = in[i].M;      
     out[i].dM    = in[i].dM;      
@@ -224,25 +187,4 @@
     out[i].Ncode = in[i].Ncode;
     out[i].Nused = in[i].Nused;
-
-    // changed or added for PS1_V1
-    out[i].M_20  = 0;      
-    out[i].M_80  = 0;      
-
-    // changed or added for PS1_V2
-    out[i].flags = 0;
-
-    // added in PS1_V3
-    out[i].Map         = 0;
-    out[i].Mstdev      = 0;
-    out[i].ubercalDist = 0;
-
-    // added for PS1_V4
-    out[i].Mkron       = NAN;
-    out[i].dMkron      = NAN;
-    out[i].FluxPSF     = NAN;
-    out[i].dFluxPSF    = NAN;
-    out[i].FluxKron    = NAN;
-    out[i].dFluxKron   = NAN;
-    out[i].stackDetectID     = 0;
  }
   return (out);
Index: /trunk/Ohana/src/libdvo/src/fits_db.c
===================================================================
--- /trunk/Ohana/src/libdvo/src/fits_db.c	(revision 34748)
+++ /trunk/Ohana/src/libdvo/src/fits_db.c	(revision 34749)
@@ -159,4 +159,10 @@
   make_backup (db[0].filename);
   Fseek (db[0].f, 0, SEEK_SET);
+
+  int fd = fileno (db->f);
+  if (ftruncate (fd, 0)) {
+    perror ("gfits_db_save: ");
+    return (FALSE);
+  }
 
   if (!gfits_fwrite_header  (db[0].f, &db[0].header)) {
Index: /trunk/Ohana/src/markrock/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/markrock/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/markrock/src/ConfigInit.c	(revision 34749)
@@ -5,5 +5,4 @@
   char *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -21,5 +20,4 @@
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
 
   /* unique to markrock */
@@ -44,6 +42,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/markstar/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/markstar/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/markstar/src/ConfigInit.c	(revision 34749)
@@ -5,5 +5,4 @@
   char *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -21,5 +20,4 @@
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
 
   sprintf (ImageCat, "%s/Images.dat", CATDIR);
@@ -54,6 +52,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/opihi/cmd.data/box.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/box.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/cmd.data/box.c	(revision 34749)
@@ -149,4 +149,30 @@
  usage:
   gprint (GP_ERR, "USAGE: box [-ticks NNNN] [-axis NNNN] [-labels NNNN]\n");
+
+  gprint (GP_ERR, "  additional options:\n");
+  gprint (GP_ERR, "  -fn (font) (size) : set font used for box\n");
+  gprint (GP_ERR, "  -lw (weight) : set box line weight\n");
+  gprint (GP_ERR, "  -c (color) : set box color\n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  for the descriptions below:\n");
+  gprint (GP_ERR, "    -x refers to the bottom x-axis, \n");
+  gprint (GP_ERR, "    -y refers to the left y-axis, \n");
+  gprint (GP_ERR, "    +x refers to the top x-axis, \n");
+  gprint (GP_ERR, "    +y refers to the right y-axis, \n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  -ticks [NNNN]  : turn on (1), off (0), or use default for ticks\n");
+  gprint (GP_ERR, "  -labels [NNNN] : turn on (1), off (0), or use default for label\n");
+  gprint (GP_ERR, "  -axis [NNNN]   : turn on (1), off (0), or use default for axis\n");
+  gprint (GP_ERR, "    the order for the NNNN values in the above options is: -x, -y, +x, +y\n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  -tickpad : set the spacing between the ticks and the tick text \n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  the following set the spacing between the label and the given axis:\n");
+  gprint (GP_ERR, "    -labelpadx, -labelpady, +labelpadx, +labelpady\n");
+  gprint (GP_ERR, "  \n");
+  gprint (GP_ERR, "  -pad : set the spacing between the plot section boundary and the axes\n");
+  gprint (GP_ERR, "         alternatively, set each axis independently with:\n");
+  gprint (GP_ERR, "        -xpad, -ypad, +xpad, +ypad\n");
+
   return (FALSE);
 }
Index: /trunk/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/avextract.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/avextract.c	(revision 34749)
@@ -137,5 +137,5 @@
   // this does all the work of re-packaging the command, calling it on the remote machines, then loading in the results
   if (PARALLEL && !HOST_ID) {
-    int status = HostTableParallelOps (argc, argv, RESULT_FILE, 0, VERBOSE);
+    int status = HostTableParallelOps (argc, argv, RESULT_FILE, TRUE, 0, VERBOSE);
 
     dbFreeFields (fields, Nfields);
@@ -325,4 +325,24 @@
     gprint (GP_ERR, "  <photcode>:nphot : number of measurements used for average magnitude in this photcode\n");
 
+    // gprint (GP_ERR, "  <photcode>:ap :  catalog aperture magnitude for photcode\n");
+    // gprint (GP_ERR, "  <photcode>:aper :  catalog aperture magnitude for photcode\n");
+    // gprint (GP_ERR, "  <photcode>:aveerr : average error (stdev)\n");
+    // gprint (GP_ERR, "  <photcode>:aperinst : aperture flux\n");
+    // gprint (GP_ERR, "  <photcode>:aper_inst : aperture flux\n");
+
+    gprint (GP_ERR, "  <photcode>:kron : kron flux\n");
+    // gprint (GP_ERR, "  <photcode>:kronerr : kron error\n");
+    gprint (GP_ERR, "  <photcode>:photflags : photometry flags for measurements\n");
+    gprint (GP_ERR, "  <photcode>:flags : photometry flags for measurements\n");
+    gprint (GP_ERR, "  <photcode>:stdev : standard deviation of measurements\n");
+    gprint (GP_ERR, "  <photcode>:20 : 20 percentile psf mag\n");
+    gprint (GP_ERR, "  <photcode>:80 : 80 percentile psf mag\n");
+    gprint (GP_ERR, "  <photcode>:ucdist : distance to ubercalibrated exposure (in exposure overlaps)\n");
+    gprint (GP_ERR, "  <photcode>:stackDetectID : PSPS ID for stack detection\n");
+    gprint (GP_ERR, "  <photcode>:fluxpsf : psf flux\n");
+    gprint (GP_ERR, "  <photcode>:fluxpsferr : psf flux error\n");
+    gprint (GP_ERR, "  <photcode>:fluxkron : kron flux\n");
+    gprint (GP_ERR, "  <photcode>:fluxkronerr : kron flux error\n");
+
     // gprint (GP_ERR, "  type : dophot type (unused)\n");
     // gprint (GP_ERR, "  typefrac : dophot type fraction (unused)\n");
Index: /trunk/Ohana/src/opihi/dvo/avmatch.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 34749)
@@ -95,5 +95,5 @@
 
     // I need to pass the RA & DEC vectors to the remote clients...
-    int status = HostTableParallelOps (argc, argv, RESULT_FILE, RAvec->Nelements, VERBOSE);
+    int status = HostTableParallelOps (argc, argv, RESULT_FILE, TRUE, RAvec->Nelements, VERBOSE);
     if (vec) free (vec);
     
Index: /trunk/Ohana/src/opihi/dvo/dvo_host_utils.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/dvo_host_utils.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/dvo_host_utils.c	(revision 34749)
@@ -79,10 +79,14 @@
 }
 
-// bundle the arguments into a command and pass to dvo_client.  this implementation
-// expects there to be a result file from the clients, and to load this into vectors in
-// the main shell.  'Nelements' is a temp hack : for most commands, the result vectors are
-// concatenated, but for avmatch, the vectors are merged by index into a pre-known
-// length.  this is probably not a solution to a general problem..
-int HostTableParallelOps (int argc, char **argv, char *ResultFile, int Nelements, int VERBOSE) {
+// bundle the arguments into a command and pass to dvo_client.  
+
+// the normal ending step expects there to be a result file from the clients, and to load
+// this into vectors in the main shell.  'Nelements' is a temp hack : for most commands,
+// the result vectors are concatenated, but for avmatch, the vectors are merged by index
+// into a pre-known length.  this is probably not a solution to a general problem..
+
+// an alternative ending step ignores the result files and instead saves the names into
+// the list 'result:n' for the user to access as desired
+int HostTableParallelOps (int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE) {
 
   int i;
@@ -153,9 +157,113 @@
   }
 
+  // create the result file list
+  char name[256];
+  snprintf (name, 256, "RESULT_FILE:n");
+  set_int_variable (name, table->Nhosts);
+  snprintf (name, 256, "RESULT_DATA:n");
+  set_int_variable (name, table->Nhosts);
+  snprintf (name, 256, "RESULT_STATUS:n");
+  set_int_variable (name, table->Nhosts);
+
   // load fields from file
   int    Nvec = 0;
   Vector **vec = NULL;
   for (i = 0; i < table->Nhosts; i++) {
+
+    snprintf (name, 256, "RESULT_FILE:%d", i);
+    set_str_variable (name, table->hosts[i].results);
+
+    // DATA : 0 (unread), 1 (read)
+    snprintf (name, 256, "RESULT_DATA:%d", i);
+    set_int_variable (name, 0);
+
+    // STATUS : 0 (normal exit), -1 (crash), N (failure exit status)
+    snprintf (name, 256, "RESULT_STATUS:%d", i);
+    set_int_variable (name, table->hosts[i].status);
+
     if (table->hosts[i].status) continue; 
+
+    if (ReadVectors) {
+      int    Ninvec = 0;
+      Vector **invec = ReadVectorTableFITS (table->hosts[i].results, "RESULT", &Ninvec);
+      if (!invec) {
+	// failed to read the file, now what?
+	gprint (GP_ERR, "failed to read remote result file : %s\n", table->hosts[i].results);
+	free (table->hosts[i].results);
+	table->hosts[i].results = NULL;
+	continue;
+      }
+      free (table->hosts[i].results);
+      table->hosts[i].results = NULL;
+      set_int_variable (name, 1); // result file has been read
+
+      if (Nelements == 0) {
+	vec = MergeVectors (vec, &Nvec, invec, Ninvec);
+	if (vec != invec) {
+	  FreeVectorArray (invec, Ninvec);
+	}
+      } else {
+	vec = MergeVectorsByIndex (vec, &Nvec, invec, Ninvec, Nelements);
+	FreeVectorArray (invec, Ninvec);
+      }
+    }
+  }
+
+  // write vectors to a table (this is used by parallel dvo operations, but can be used elsewhere)
+  if (ResultFile) {
+    int status = WriteVectorTableFITS (ResultFile, "RESULT", vec, Nvec, FALSE, NULL);
+    if (!status) {
+      gprint (GP_ERR, "failed to write result file %s\n", ResultFile);
+      return FALSE;
+    }
+  }
+
+  for (i = 0; i < Nvec; i++) {
+    AssignVector (vec[i], vec[i]->name, ANYVECTOR, TRUE);
+  }
+  free (vec);
+
+  free (table);
+  return TRUE;
+}
+
+// re-gather the remote results files: this can be used in case one of the clients failed,
+// and has since been re-run
+int HostTableReloadResults (char *uniquer, int VERBOSE) {
+
+  int i;
+
+  // load the list of hosts
+  SkyTable *sky = GetSkyTable();
+  if (!sky) {
+    gprint (GP_ERR, "failed to load sky table for database\n");
+    return FALSE;
+  }
+
+  char *CATDIR = GetCATDIR ();
+  if (!CATDIR) {
+    gprint (GP_ERR, "failed to get CATDIR for database\n");
+    return FALSE;
+  }
+
+  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
+  if (!table) {
+    gprint (GP_ERR, "ERROR: failure reading Host Table %s for database %s\n", sky->hosts, CATDIR);
+    return FALSE;
+  }    
+
+  // load fields from file
+  int    Nvec = 0;
+  Vector **vec = NULL;
+  for (i = 0; i < table->Nhosts; i++) {
+    // ensure that the paths are absolute path names
+    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
+    free (table->hosts[i].pathname);
+    table->hosts[i].pathname = tmppath;
+
+    // need to save the results filename with the uniquer
+    // XXX a bit of a waste (but only 1024 * 60 bytes or so
+    ALLOCATE (table->hosts[i].results, char, DVO_MAX_PATH);
+    snprintf (table->hosts[i].results, DVO_MAX_PATH, "%s/dvo.results.%s.fits", table->hosts[i].pathname, uniquer);
 
     int    Ninvec = 0;
@@ -171,21 +279,9 @@
     table->hosts[i].results = NULL;
 
-    if (Nelements == 0) {
-      vec = MergeVectors (vec, &Nvec, invec, Ninvec);
-      if (vec != invec) {
-	FreeVectorArray (invec, Ninvec);
-      }
-    } else {
-      vec = MergeVectorsByIndex (vec, &Nvec, invec, Ninvec, Nelements);
+    // fprintf (stderr, "%s : %d\n", table->hosts[i].pathname, invec[0]->Nelements);
+
+    vec = MergeVectors (vec, &Nvec, invec, Ninvec);
+    if (vec != invec) {
       FreeVectorArray (invec, Ninvec);
-    }
-  }
-
-  // write vectors to a table (this is used by parallel dvo operations, but can be used elsewhere)
-  if (ResultFile) {
-    int status = WriteVectorTableFITS (ResultFile, "RESULT", vec, Nvec, FALSE, NULL);
-    if (!status) {
-      gprint (GP_ERR, "failed to write result file %s\n", ResultFile);
-      return FALSE;
     }
   }
@@ -199,70 +295,2 @@
   return TRUE;
 }
-
-// re-gather the remote results files: this can be used in case one of the clients failed,
-// and has since been re-run
-int HostTableReloadResults (char *uniquer, int VERBOSE) {
-
-  int i;
-
-  // load the list of hosts
-  SkyTable *sky = GetSkyTable();
-  if (!sky) {
-    gprint (GP_ERR, "failed to load sky table for database\n");
-    return FALSE;
-  }
-
-  char *CATDIR = GetCATDIR ();
-  if (!CATDIR) {
-    gprint (GP_ERR, "failed to get CATDIR for database\n");
-    return FALSE;
-  }
-
-  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
-  if (!table) {
-    gprint (GP_ERR, "ERROR: failure reading Host Table %s for database %s\n", sky->hosts, CATDIR);
-    return FALSE;
-  }    
-
-  // load fields from file
-  int    Nvec = 0;
-  Vector **vec = NULL;
-  for (i = 0; i < table->Nhosts; i++) {
-    // ensure that the paths are absolute path names
-    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
-    free (table->hosts[i].pathname);
-    table->hosts[i].pathname = tmppath;
-
-    // need to save the results filename with the uniquer
-    // XXX a bit of a waste (but only 1024 * 60 bytes or so
-    ALLOCATE (table->hosts[i].results, char, DVO_MAX_PATH);
-    snprintf (table->hosts[i].results, DVO_MAX_PATH, "%s/dvo.results.%s.fits", table->hosts[i].pathname, uniquer);
-
-    int    Ninvec = 0;
-    Vector **invec = ReadVectorTableFITS (table->hosts[i].results, "RESULT", &Ninvec);
-    if (!invec) {
-      // failed to read the file, now what?
-      gprint (GP_ERR, "failed to read remote result file : %s\n", table->hosts[i].results);
-      free (table->hosts[i].results);
-      table->hosts[i].results = NULL;
-      continue;
-    }
-    free (table->hosts[i].results);
-    table->hosts[i].results = NULL;
-
-    // fprintf (stderr, "%s : %d\n", table->hosts[i].pathname, invec[0]->Nelements);
-
-    vec = MergeVectors (vec, &Nvec, invec, Ninvec);
-    if (vec != invec) {
-      FreeVectorArray (invec, Ninvec);
-    }
-  }
-
-  for (i = 0; i < Nvec; i++) {
-    AssignVector (vec[i], vec[i]->name, ANYVECTOR, TRUE);
-  }
-  free (vec);
-
-  free (table);
-  return TRUE;
-}
Index: /trunk/Ohana/src/opihi/dvo/mextract.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/mextract.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/mextract.c	(revision 34749)
@@ -108,5 +108,5 @@
   // this does all the work of re-packaging the command, calling it on the remote machines, then loading in the results
   if (PARALLEL && !HOST_ID) {
-    int status = HostTableParallelOps (argc, argv, RESULT_FILE, 0, VERBOSE);
+    int status = HostTableParallelOps (argc, argv, RESULT_FILE, TRUE, 0, VERBOSE);
 
     dbFreeFields (fields, Nfields);
@@ -313,7 +313,8 @@
     gprint (GP_ERR, "  Npos  : number of measurments used for astrometry\n");
 
-    gprint (GP_ERR, "  objflags  : object flags\n");
-    gprint (GP_ERR, "  photflags : detection flags from image analysis\n");
-    gprint (GP_ERR, "  dbflags : detection flags from database analysis\n");
+    gprint (GP_ERR, "  objflags  : object flags [alias: obj_flags]\n");
+    gprint (GP_ERR, "  secflags  : average photometry flags [aliases: obj_phot_flags, sec_flags, secfilt_flags]\n");
+    gprint (GP_ERR, "  photflags : detection flags from image analysis [alias: phot_flags]\n");
+    gprint (GP_ERR, "  dbflags : detection flags from database analysis [alias: db_flags]\n");
 
     gprint (GP_ERR, "  obj_flags : object flags\n");
@@ -321,4 +322,73 @@
     gprint (GP_ERR, "  db_flags : detection flags from database analysis\n");
 
+    gprint (GP_ERR, "  airmass : airmass of detection\n");
+    gprint (GP_ERR, "  meas_airmass : airmass of exposure\n");
+    gprint (GP_ERR, "  alt : altitude of detection\n");
+    gprint (GP_ERR, "  az  : azimuth of detection\n");
+    gprint (GP_ERR, "  exptime : exposure time [s]\n");
+    gprint (GP_ERR, "  photcode : photcode \n");
+    gprint (GP_ERR, "  photcode:equiv : equivalent average photcode \n");
+    gprint (GP_ERR, "  photcode:c : zero point of photcode \n");
+    gprint (GP_ERR, "  photcode:klam : airmass slope of photcode \n");
+    gprint (GP_ERR, "  time : time of exposure [Seconds since Jan 1, 1970/\n");
+    gprint (GP_ERR, "  fwhm : fwhm (average) of fitted PSF [pixels]\n");
+    gprint (GP_ERR, "  fwhm_maj : fwhm (major axis) of fitted PSF [pixels]\n");
+    gprint (GP_ERR, "  fwhm_min : fwhm (minor axis) of fitted PSF [pixels]\n");
+    gprint (GP_ERR, "  theta : position angle of fitted PSF\n");
+    gprint (GP_ERR, "  posangle : position angle of detector at measurement [degrees]\n");
+    gprint (GP_ERR, "  platescale : plate scale of detector at measurement [arcsec/pixel] (negative = sky parity)\n");
+
+    gprint (GP_ERR, "  Mxx : second moment in X [pixels^2]\n");
+    gprint (GP_ERR, "  Mxy : second moment cross term [pixels^2]\n");
+    gprint (GP_ERR, "  Myy : second moment in Y [pixels^2]\n");
+
+    gprint (GP_ERR, "  xccd : ccd x position\n");
+    gprint (GP_ERR, "  yccd : ccd y position\n");
+    gprint (GP_ERR, "  xoff : ccd x correction\n");
+    gprint (GP_ERR, "  yoff : ccd y correction\n");
+    gprint (GP_ERR, "  xccd:err : ccd x position error\n");
+    gprint (GP_ERR, "  yccd:err : ccd y position error\n");
+
+    gprint (GP_ERR, "  pos_sys_err : systematic position error\n");
+
+    gprint (GP_ERR, "  xmosaic : mosaic x position\n");
+    gprint (GP_ERR, "  ymosaic : mosaic y position\n");
+
+    gprint (GP_ERR, "  xchip : chip x position (= ccd position)\n");
+    gprint (GP_ERR, "  ychip : chip y position (= ccd position)\n");
+    gprint (GP_ERR, "  xfpa : fpa x position (= mosaic position)\n");
+    gprint (GP_ERR, "  yfpa : fpa y position (= mosaic position)\n");
+
+    gprint (GP_ERR, "  detID : ID of detection (unique on source image)\n");
+    gprint (GP_ERR, "  objID : object ID (32 bit, unique in catalog)\n");
+    gprint (GP_ERR, "  catID : catalog ID (32 bit)\n");
+    gprint (GP_ERR, "  imageID : ID of source image (32 bit)\n");
+    gprint (GP_ERR, "  externID : externID of source image (32 bit)\n");
+
+    gprint (GP_ERR, "  psf_qf : PSF quality factor (psf-weighted mask fraction)\n");
+    gprint (GP_ERR, "  psf_qf_perfect : PSF quality factor, perfect mask version (psf-weighted mask fraction)\n");
+
+    gprint (GP_ERR, "  psf_chisq : PSF fit chi square\n");
+    gprint (GP_ERR, "  psf_ndof : PSF number of degrees of freedom\n");
+    gprint (GP_ERR, "  psf_npix : PSF number of pixels\n");
+
+    gprint (GP_ERR, "  cr_nsigma : Nsigma deviation towards cosmic ray\n");
+    gprint (GP_ERR, "  ext_nsigma : Nsigma deviation towards extended source\n");
+
+    gprint (GP_ERR, "  sky : sky model flux at measurement location\n");
+    gprint (GP_ERR, "  sky_err : sky model stdev at measurement location\n");
+
+    gprint (GP_ERR, "  Mcal_offset : difference wrt nominal zero point (clouds are positive)\n");
+    gprint (GP_ERR, "  flat : flat-field correction (measure.Mcal - image.Mcal)\n");
+
+    gprint (GP_ERR, "  center_offset : distance to image center\n");
+    gprint (GP_ERR, "  flux : PSF flux\n");
+    gprint (GP_ERR, "  flux_err : PSF flux error\n");
+    gprint (GP_ERR, "  flux_psf : PSF flux\n");
+    gprint (GP_ERR, "  flux_psf_err : PSF flux error\n");
+    gprint (GP_ERR, "  flux_kron : KRON flux\n");
+    gprint (GP_ERR, "  flux_kron_err : KRON flux error\n");
+
+    gprint (GP_ERR, "  --- the following fields are selected by giving a photcode with the attached ending\n");
     gprint (GP_ERR, "  <photcode>:ave : average magnitude for photcode (or equivalent)\n");
     gprint (GP_ERR, "  <photcode>:ref : reference magnitude system for photcode (or equivalent)\n");
@@ -335,49 +405,19 @@
     gprint (GP_ERR, "  <photcode>:ncode : number of measurements in photcode\n");
     gprint (GP_ERR, "  <photcode>:nphot : number of measurements used for average magnitude\n");
-    gprint (GP_ERR, "  airmass : airmass of detection\n");
-    gprint (GP_ERR, "  alt : altitude of detection\n");
-    gprint (GP_ERR, "  az  : azimuth of detection\n");
-    gprint (GP_ERR, "  exptime : exposure time [s]\n");
-    gprint (GP_ERR, "  photcode : photcode \n");
-    gprint (GP_ERR, "  photcode:equiv : equivalent average photcode \n");
-    gprint (GP_ERR, "  time : time of exposure [Seconds since Jan 1, 1970/\n");
-    gprint (GP_ERR, "  fwhm : fwhm (average) of fitted PSF [pixels]\n");
-    gprint (GP_ERR, "  fwhm_maj : fwhm (major axis) of fitted PSF [pixels]\n");
-    gprint (GP_ERR, "  fwhm_min : fwhm (minor axis) of fitted PSF [pixels]\n");
-    gprint (GP_ERR, "  theta : position angle of fitted PSF\n");
-    gprint (GP_ERR, "  posangle : position angle of detector at measurement [degrees]\n");
-    gprint (GP_ERR, "  platescale : plate scale of detector at measurement [arcsec/pixel] \n");
-
-    gprint (GP_ERR, "  psf_qf : PSF quality factor (psf-weighted mask fraction)\n");
-    gprint (GP_ERR, "  psf_chisq : PSF fit chi square\n");
-    gprint (GP_ERR, "  psf_ndof : PSF number of degrees of freedom\n");
-    gprint (GP_ERR, "  psf_npix : PSF number of pixels\n");
-
-    gprint (GP_ERR, "  cr_nsigma : Nsigma deviation towards cosmic ray\n");
-    gprint (GP_ERR, "  ext_nsigma : Nsigma deviation towards extended source\n");
-
-    gprint (GP_ERR, "  Mxx : second moment in X [pixels^2]\n");
-    gprint (GP_ERR, "  Mxy : second moment cross term [pixels^2]\n");
-    gprint (GP_ERR, "  Myy : second moment in Y [pixels^2]\n");
-
-    gprint (GP_ERR, "  xccd : ccd x position\n");
-    gprint (GP_ERR, "  yccd : ccd y position\n");
-    gprint (GP_ERR, "  xccd:err : ccd x position error\n");
-    gprint (GP_ERR, "  yccd:err : ccd y position error\n");
-    gprint (GP_ERR, "  xmosaic : mosaic x position\n");
-    gprint (GP_ERR, "  ymosaic : mosaic y position\n");
-    gprint (GP_ERR, "  xchip : chip x position (= ccd position)\n");
-    gprint (GP_ERR, "  ychip : chip y position (= ccd position)\n");
-    gprint (GP_ERR, "  xfpa : fpa x position (= mosaic position)\n");
-    gprint (GP_ERR, "  yfpa : fpa y position (= mosaic position)\n");
-
-    gprint (GP_ERR, "  detID : ID of detection (unique on source image)\n");
-    gprint (GP_ERR, "  objID : object ID (32 bit, unique in catalog)\n");
-    gprint (GP_ERR, "  catID : catalog ID (32 bit)\n");
-    gprint (GP_ERR, "  imageID : ID of source image (32 bit)\n");
-    gprint (GP_ERR, "  externID : externID of source image (32 bit)\n");
-
-    gprint (GP_ERR, "  Mcal_offset : difference wrt nominal zero point (clouds are positive)\n");
-    gprint (GP_ERR, "  flat : flat-field correction (measure.Mcal - image.Mcal)\n");
+
+    gprint (GP_ERR, "  <photcode>:aperinst : instrumental aperture magnitude\n");
+    gprint (GP_ERR, "  <photcode>:aper_inst : instrumental aperture magnitude\n");
+    gprint (GP_ERR, "  <photcode>:kron : kron mag\n");
+    gprint (GP_ERR, "  <photcode>:kroninst : instrumental kron mag\n");
+    gprint (GP_ERR, "  <photcode>:kron_inst : instrumental kron mag\n");
+    gprint (GP_ERR, "  <photcode>:kronerr : kron mag error\n");
+
+    gprint (GP_ERR, "  <photcode>:photflags : photometry flags for measurements\n");
+    gprint (GP_ERR, "  <photcode>:flags : photometry flags for measurements\n");
+    gprint (GP_ERR, "  <photcode>:fluxpsf : average psf flux\n");
+    gprint (GP_ERR, "  <photcode>:fluxpsferr : average psf flux error\n");
+    gprint (GP_ERR, "  <photcode>:fluxkron : average kron flux\n");
+    gprint (GP_ERR, "  <photcode>:fluxkronerr : average kron flux error\n");
+
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/dvo/mmatch.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/mmatch.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/mmatch.c	(revision 34749)
@@ -124,5 +124,5 @@
 
     // call the remote client
-    int status = HostTableParallelOps (targc, targv, RESULT_FILE, 0, VERBOSE);
+    int status = HostTableParallelOps (targc, targv, RESULT_FILE, TRUE, 0, VERBOSE);
     if (vec) free (vec);
     
Index: /trunk/Ohana/src/opihi/dvo/remote.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/remote.c	(revision 34748)
+++ /trunk/Ohana/src/opihi/dvo/remote.c	(revision 34749)
@@ -12,4 +12,10 @@
     remove_argument (N, &argc, argv);
     VERBOSE = TRUE;
+  }
+
+  int ReadVectors = TRUE;
+  if ((N = get_argument (argc, argv, "-skip-result"))) {
+    remove_argument (N, &argc, argv);
+    ReadVectors = FALSE;
   }
 
@@ -43,5 +49,5 @@
 
   // strip of the 'remote' and send the remaining arguments to the remote machine
-  int status = HostTableParallelOps (argc - 1, &argv[1], NULL, 0, VERBOSE);
+  int status = HostTableParallelOps (argc - 1, &argv[1], NULL, ReadVectors, 0, VERBOSE);
   return status;
 }
Index: /trunk/Ohana/src/opihi/include/dvoshell.h
===================================================================
--- /trunk/Ohana/src/opihi/include/dvoshell.h	(revision 34748)
+++ /trunk/Ohana/src/opihi/include/dvoshell.h	(revision 34749)
@@ -100,5 +100,5 @@
 
 int          HostTableLaunchJobs    PROTO((HostTable *table, char *basecmd, char *options, int VERBOSE));
-int          HostTableParallelOps   PROTO((int argc, char **argv, char *ResultFile, int Nelements, int VERBOSE));
+int          HostTableParallelOps   PROTO((int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE));
 int          HostTableReloadResults PROTO((char *uniquer, int VERBOSE));
 
Index: /trunk/Ohana/src/photdbc/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/photdbc/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/photdbc/src/ConfigInit.c	(revision 34749)
@@ -14,5 +14,4 @@
   char *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -60,6 +59,4 @@
   free (tmpcatdir);
 
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
-
   sprintf (ImageCat, "%s/Images.dat", CATDIR);
 
@@ -73,5 +70,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, TRUE)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
     fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
Index: /trunk/Ohana/src/relastro/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/relastro/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/relastro/src/ConfigInit.c	(revision 34749)
@@ -5,5 +5,4 @@
   char  *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
   struct stat filestat;
   int status;
@@ -46,5 +45,4 @@
   ScanConfig(config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig(config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig(config, "PHOTCODE_FILE",          "%s",  0, MasterPhotcodeFile);
 
   // Defaults for WHERE_A are established in db_utils.c: intializeConstraints
@@ -73,6 +71,6 @@
   /* update master photcode table if not defined */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/relastro/src/ImageOps.c
===================================================================
--- /trunk/Ohana/src/relastro/src/ImageOps.c	(revision 34748)
+++ /trunk/Ohana/src/relastro/src/ImageOps.c	(revision 34749)
@@ -174,7 +174,13 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Nmeasure; j++) {
-      // XXX : update to optionally restrict by photcode equiv a la relphot
-      // ecode = GetPhotcodeEquivCodebyCode (catalog[i].measure[j].photcode);
-      // if (photcode[0].code != ecode) continue;
+      if (NphotcodesSkip > 0) {
+	int k;
+	int found = FALSE;
+	for (k = 0; (k < NphotcodesSkip) && !found; k++) {
+	  if (photcodesSkip[k][0].code == catalog[i].measure[j].photcode) found = TRUE;
+	  if (photcodesSkip[k][0].code == GetPhotcodeEquivCodebyCode(catalog[i].measure[j].photcode)) found = TRUE;
+	}
+	if (found) continue;
+      }  
       matchImage (catalog, j, i, MATCHCAT);
     }
Index: /trunk/Ohana/src/relastro/src/UpdateObjects.c
===================================================================
--- /trunk/Ohana/src/relastro/src/UpdateObjects.c	(revision 34748)
+++ /trunk/Ohana/src/relastro/src/UpdateObjects.c	(revision 34749)
@@ -112,5 +112,6 @@
 	if (XVERB) {
 	  char *date = ohana_sec_to_date (measure[k].t);
-	  fprintf (stderr, OFF_T_FMT" %f %f %s : 0x%08x : 0x%08x\n",  k, measure[k].dR, measure[k].dD, date, measure[k].dbFlags, measureBig[k].dbFlags);
+	  int dbFlagsBig = measureBig ? measureBig[k].dbFlags : 0;
+	  fprintf (stderr, OFF_T_FMT" %f %f %s : 0x%08x : 0x%08x\n",  k, measure[k].dR, measure[k].dD, date, measure[k].dbFlags, dbFlagsBig);
 	  free (date);
 	}
Index: /trunk/Ohana/src/relastro/src/args.c
===================================================================
--- /trunk/Ohana/src/relastro/src/args.c	(revision 34748)
+++ /trunk/Ohana/src/relastro/src/args.c	(revision 34749)
@@ -237,8 +237,19 @@
   }
 
-  PHOTCODE_SKIP_LIST = NULL;
+  PHOTCODE_SKIP_LIST = strcreate("SCOS.103a.E,SCOS.4414.OG590,SCOS.4415.OG590,SCOS.IIIaF.OG590,SCOS.IIIaF.RG610,SCOS.IIIaF.RG630,SCOS.IIIaJ.GG385,SCOS.IIIaJ.GG395,SCOS.IVN.RG715,SCOS.IVN.RG9");
   if ((N = get_argument (argc, argv, "-photcode"))) {
     remove_argument (N, &argc, argv);
-    PHOTCODE_SKIP_LIST = strcreate(argv[N]);
+    char *tmp1 = strcreate(argv[N]);
+
+    int Ntotal = strlen(tmp1) + strlen(PHOTCODE_SKIP_LIST) + 5;
+
+    char *tmp2 = NULL;
+    ALLOCATE (tmp2, char, Ntotal);
+    snprintf (tmp2, Ntotal, "%s,%s", PHOTCODE_SKIP_LIST, tmp1);
+
+    free (tmp1);
+    free (PHOTCODE_SKIP_LIST);
+
+    PHOTCODE_SKIP_LIST = tmp2;
     remove_argument (N, &argc, argv);
   }
Index: /trunk/Ohana/src/relphot/src/ConfigInit.c
===================================================================
--- /trunk/Ohana/src/relphot/src/ConfigInit.c	(revision 34748)
+++ /trunk/Ohana/src/relphot/src/ConfigInit.c	(revision 34749)
@@ -6,5 +6,4 @@
   char  *config, *file;
   char CatdirPhotcodeFile[256];
-  char MasterPhotcodeFile[256];
 
   /*** load configuration info ***/
@@ -45,7 +44,6 @@
   ScanConfig (config, "CATMODE",                "%s",  0, CATMODE);
   ScanConfig (config, "CATFORMAT",              "%s",  0, CATFORMAT);
-  ScanConfig (config, "PHOTCODE_FILE",         	"%s",  0, MasterPhotcodeFile);
 
-  sprintf (ImageCat, "%s/Images.dat", CATDIR);
+  snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", CATDIR);
 
   if (!ScanConfig (config, "SKY_DEPTH",         "%d",  0, &SKY_DEPTH)) {
@@ -69,6 +67,6 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
-    fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
   }
Index: /trunk/Ohana/src/relphot/src/StarOps.c
===================================================================
--- /trunk/Ohana/src/relphot/src/StarOps.c	(revision 34748)
+++ /trunk/Ohana/src/relphot/src/StarOps.c	(revision 34749)
@@ -356,6 +356,4 @@
 
   for (j = 0; j < catalog[Nc].Naverage; j++) {
-    // XXX accumulate all secfilt values in a single pass?
-
     // option for a test print
     if (FALSE && (catalog[Nc].average[j].objID == 0x7146) && (catalog[Nc].average[j].catID == 0x49d8)) {
@@ -376,4 +374,9 @@
 
     int Nmeas = 0; // number of meas used for psfqf, psfqfperf, and stargal
+
+    int NstackGood = 0;
+    int NstackSuspect = 0;
+
+    int haveStackObject = FALSE;
 
     int Ns;
@@ -401,9 +404,7 @@
 
       float stackCenterOffsetMin = 1e9;
-      // int stackCenterIDmin = -1;
       off_t stackCenterMeasureMin = -1;
 
       float stackPrimaryOffsetMin = 1e9;
-      // int stackPrimaryIDmin = -1;
       off_t stackPrimaryMeasureMin = -1;
 
@@ -415,4 +416,7 @@
       int minUbercalDist = 1000;
     
+      int isBad = FALSE;
+      int isSuspect = FALSE;
+
       N = 0;
       m = catalog[Nc].averageT[j].measureOffset;
@@ -447,23 +451,8 @@
 	if (isnan(Msys)) SKIP_THIS_MEAS(Nsys);
 
-	list[N] = Msys - Mcal - Mmos - Mgrid;
-
 	int myUbercalDist = getUbercalDist(m,Nc);
 	minUbercalDist = MIN(minUbercalDist, myUbercalDist);
 
 	if (isSetMrelFinal) {
-	  // Map (aplist) and Mkron (kronlist,dkronlist) are used to calculate mean mags per filter
-	  float Map = PhotAper (&catalog[Nc].measure[m]);
-	  aplist[N] = Map - Mcal - Mmos - Mgrid;
-
-	  float Mkron = PhotKron (&catalog[Nc].measure[m]);
-	  kronlist[N] = Mkron - Mcal - Mmos - Mgrid;
-	  dkronlist[N] = catalog[Nc].measure[m].dMkron;
-
-	  // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters)
-	  psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
-	  psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQF;
-	  stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
-
 	  // special options for PS1 data
 	  if ((catalog[Nc].measure[m].photcode >= 10000) && (catalog[Nc].measure[m].photcode <= 10500)) {
@@ -484,8 +473,9 @@
 	    havePS1 = TRUE;
 	  }
+
 	  // gpc1 stack data
 	  if ((catalog[Nc].measure[m].photcode >= 11000) && (catalog[Nc].measure[m].photcode <= 11400)) {
-	    // if (pass < 2) continue;
 	    haveStack = TRUE;
+	    haveStackObject = TRUE;
 
 	    unsigned int stackImageID;
@@ -509,4 +499,21 @@
 	      stackCenterMeasureMin = m;
 	    }
+
+	    // data quality assessment
+	    isBad |= (catalog[Nc].measure[m].photFlags & code->photomBadMask);
+	    isBad |= (catalog[Nc].measure[m].psfQF < 0.85);
+	    isBad |= isnan(catalog[Nc].measure[m].psfQF);
+	    isBad |= catalog[Nc].measure[m].dM > 0.2; // S/N < 5.0
+
+	    isSuspect |= (catalog[Nc].measure[m].photFlags & code->photomPoorMask);
+	    isSuspect |= (catalog[Nc].measure[m].psfQFperf < 0.85);
+
+	    // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters, stacks and exposures)
+	    psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
+	    psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQFperf;
+	    stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
+	    Nmeas++;
+
+	    continue; // do not include stack measurements in the per-exposure statistics
 	  }
 
@@ -523,5 +530,4 @@
 		// detections without one of these bits should only be used in PASS_1
 		SKIP_THIS_MEAS(Nbad);
-		continue;
 	      }
 	    }
@@ -557,9 +563,22 @@
 	      if (pass < 4) {
 		SKIP_THIS_MEAS(Nbad);
-		continue;
 	      }
 	      haveSynth = TRUE;
 	    }
 	  }
+
+	  // Map (aplist) and Mkron (kronlist,dkronlist) are used to calculate mean mags per filter
+	  float Map = PhotAper (&catalog[Nc].measure[m]);
+	  aplist[N] = Map - Mcal - Mmos - Mgrid;
+
+	  float Mkron = PhotKron (&catalog[Nc].measure[m]);
+	  kronlist[N] = Mkron - Mcal - Mmos - Mgrid;
+	  dkronlist[N] = catalog[Nc].measure[m].dMkron;
+
+	  // mean psfQF, psfQFperf, and stargal values are calculated per object (all filters, stacks and exposures)
+	  psfqf_list[Nmeas]     = catalog[Nc].measure[m].psfQF;
+	  psfqfperf_list[Nmeas] = catalog[Nc].measure[m].psfQFperf;
+	  stargal_list[Nmeas]   = catalog[Nc].measure[m].extNsigma;
+	  Nmeas++;
 	}
 
@@ -572,4 +591,5 @@
 	dlist[N] = MAX (hypot(catalog[Nc].measureT[m].dM, code->photomErrSys), MIN_ERROR);
 	wlist[N] = 1.0;
+	list[N]  = Msys - Mcal - Mmos - Mgrid;
 
 	// up-weight the ubercal values (or convergence can take a long time...)
@@ -588,5 +608,4 @@
 	}
 	N++;
-	Nmeas++;
       }
 
@@ -595,4 +614,13 @@
       if (haveStack && (N > 1)) {
 	// fprintf (stderr, "multiple stack values for %10.6f %10.6f\n", catalog[Nc].averageT[j].R, catalog[Nc].averageT[j].D);
+      }
+
+      if (haveStack) {
+	if (!isSuspect && !isBad) {
+	  NstackGood ++;
+	}
+	if (isSuspect && !isBad) {
+	  NstackSuspect ++;
+	}
       }
 
@@ -764,4 +792,12 @@
       }
 
+      if (NstackGood >= 2) {
+	catalog[Nc].average[j].flags |= ID_OBJ_GOOD_STACK;
+      } else if (NstackGood + NstackSuspect >= 2) {
+	catalog[Nc].average[j].flags |= ID_OBJ_SUSPECT_STACK;
+      } else if (haveStackObject) {
+	catalog[Nc].average[j].flags |= ID_OBJ_BAD_STACK;
+      }
+
       // use NAN values for catalog[Nc].average[j].psfQF as signal
       if (!isfinite(catalog[Nc].average[j].psfQF)) {
Index: /trunk/Ohana/src/relphot/src/setMrelFinal.c
===================================================================
--- /trunk/Ohana/src/relphot/src/setMrelFinal.c	(revision 34748)
+++ /trunk/Ohana/src/relphot/src/setMrelFinal.c	(revision 34749)
@@ -40,15 +40,5 @@
       for (i = 0; i < catalog[0].Naverage; i++) {
 	off_t N = Nsecfilt*i+Nsec;
-	catalog[0].secfilt[N].M      = NAN;
-	catalog[0].secfilt[N].Map    = NAN;
-	catalog[0].secfilt[N].dM     = NAN;
-	catalog[0].secfilt[N].Mstdev = NAN_S_SHORT;
-	catalog[0].secfilt[N].Xm     = NAN;
-	catalog[0].secfilt[N].M_20   = NAN_S_SHORT;
-	catalog[0].secfilt[N].M_80   = NAN_S_SHORT;
-	catalog[0].secfilt[N].Ncode  = 0;
-	catalog[0].secfilt[N].Nused  = 0;
-	catalog[0].secfilt[N].flags  = 0; // XXX there are no *astrometry* bits in secfilt.flags
-	catalog[0].secfilt[N].ubercalDist = 1000;
+	dvo_secfilt_init (&catalog[0].secfilt[N]);
 
 	off_t m = catalog[0].average[i].measureOffset;
@@ -247,5 +237,5 @@
 	}
 	
-	// PASS 2 : accept stack measurements
+	// PASS 2 : (no additional cut)
 
 	// PASS 1 : accept poor measurements as well (eg, POOR FIT, etc)
Index: /trunk/Ohana/src/shell/src/bbc.jpegs
===================================================================
--- /trunk/Ohana/src/shell/src/bbc.jpegs	(revision 34749)
+++ /trunk/Ohana/src/shell/src/bbc.jpegs	(revision 34749)
@@ -0,0 +1,147 @@
+#!/usr/bin/env mana
+
+# USAGE: bbc.jpegs NX NY (output) (expname) (expname) (expname) (expname) ... [number of exposures is arbitrary?)
+
+# create the output directory
+# loop over the exposures
+#   use warptool to select the list of warp skycells for each exposure
+#   loop over the skycells
+#     read the skycell pixels
+#     subset into NX x NY pieces
+#     write each jpeg to expname.skycell.xy.jpeg
+#     extract the WCS from the skycell header
+#     write the WCS to the output manifest file
+#  tar the directory?
+
+macro outer.loop
+  $NX = $argv:0
+  $NY = $argv:1
+  $outdir = $argv:2
+  $KAPA = kapa -noX
+  mkdir $outdir
+
+  for i 3 $argv:n
+    mkjpegs $argv:$i
+  end
+
+  exec tar cvzf $outdir.tgz $outdir
+end
+
+macro mkjpegs
+  if ($0 != 2)
+    echo "USAGE: mkjpegs (path_base)"
+    break
+  end
+
+  echo "mkjpegs $1"
+  
+  # read in the image
+  # split into NX x NY images
+  
+  rd skycell -x 0 $1.fits
+  keyword skycell NAXIS1 Nx
+  keyword skycell NAXIS2 Ny
+
+  $dX = int($Nx / $NX)
+  $dY = int($Ny / $NY)
+
+  # resize the display to match $dX,dY
+
+  for ix 0 $NX
+    for iy 0 $NY
+      delete -q out 
+      extract skycell out {$ix*$dX} {$iy*$dY} $dX $dY 0 0 $dX $dY
+      stats -q out
+      tv out -50 500
+      jpeg -name $outdir/skycell.$ix.$iy.jpg
+    end
+  end
+end
+
+macro get.skycells
+  if ($0 != 2)
+    echo "USAGE: mkjpegs (expname)"
+    break
+  end
+
+  # saves result in $warp_id
+  get.warpid $1
+
+  queueload warplist_queue -x "warptool -dbname gpc1 -warped -exp_name $1 -warp_id $warp_id"
+  # XXX check for no output
+
+  # XXX need to move ipptool2book from pantasks to cmd.data
+  ipptool2book warplist_queue warplist
+
+  # select the skycells
+  book npages warplist -var npages
+  if ($npages == 0) 
+    echo "no warped skycells for $1"
+    break
+  end
+
+  for i 0 $npages
+    sprint page page.%03d $i
+    book getword warplist $page path_base -var path_base
+    book getword warplist $page quality -var quality
+    book getword warplist $page maskfrac_static -var mask_static
+
+    if ($quality > 0) continue
+    if ($mask_static > 0.15) continue
+    
+    echo mkjpegs $quality $mask_static $path_base
+    mkjpegs $path_base
+  end
+end
+
+macro get.warpid
+  if ($0 != 2)
+    echo "USAGE: get.warpid (expname)"
+    break
+  end
+
+  queueload warprun_queue -x "warptool -dbname gpc1 -listrun -exp_name $1"
+  # XXX check for no output
+
+  # XXX need to move ipptool2book from pantasks to cmd.data
+  ipptool2book warprun_queue warprun
+
+  # select the earliest warp run
+  book npages warprun -var npages
+  if ($npages == 0) 
+    echo "no warp runs for $1"
+    break
+  end
+
+  for i 0 $npages
+    sprint page page.%03d $i
+    book getword warprun $page warp_id -var warp_id:$i
+    book getword warprun $page state   -var state:$i
+  end
+
+  $minN  = 0
+  $minID = $warp_id:0
+  for i 1 $npages
+    if ($warp_id:$i > $minID) continue
+    $minN  = $i
+    $minID = $warp_id:$i
+  end
+  
+  if ($state:$minN != "full") 
+    echo "selected warp is not in state 'full'"
+    break
+  end  
+
+  $warp_id = $minID
+end
+
+if ($SCRIPT) 
+  if ($argv:n < 4)
+    echo "USAGE: bbc.jpegs NX NY (output) (expname) (expname) (expname) (expname) ..."
+    break
+  end
+
+  outer.loop
+  exit 0
+end
+
Index: /trunk/Ohana/src/uniphot/Makefile
===================================================================
--- /trunk/Ohana/src/uniphot/Makefile	(revision 34748)
+++ /trunk/Ohana/src/uniphot/Makefile	(revision 34749)
@@ -21,6 +21,8 @@
 setphot: $(BIN)/setphot.$(ARCH)
 setphot_client: $(BIN)/setphot_client.$(ARCH)
+setposangle: $(BIN)/setposangle.$(ARCH)
+setposangle_client: $(BIN)/setposangle_client.$(ARCH)
 
-install: $(DESTBIN)/uniphot $(DESTBIN)/setfwhm $(DESTBIN)/setphot $(DESTBIN)/setphot_client
+install: $(DESTBIN)/uniphot $(DESTBIN)/setfwhm $(DESTBIN)/setphot $(DESTBIN)/setphot_client $(DESTBIN)/setposangle $(DESTBIN)/setposangle_client
 
 UNIPHOT = \
@@ -71,4 +73,30 @@
 $(BIN)/setphot_client.$(ARCH): $(SETPHOT_CLIENT)
 
+SETPOSANGLE = \
+$(SRC)/setposangle.$(ARCH).o	    \
+$(SRC)/initialize_setposangle.$(ARCH).o \
+$(SRC)/load_images_setposangle.$(ARCH).o \
+$(SRC)/ImageSubsetSetPosangle.$(ARCH).o	    \
+$(SRC)/update_dvo_setposangle.$(ARCH).o \
+$(SRC)/update_catalog_setposangle.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o	    \
+$(SRC)/Shutdown.$(ARCH).o	    
+
+$(SETPOSANGLE): $(INC)/setposangle.h
+$(BIN)/setposangle.$(ARCH): $(SETPOSANGLE)
+
+SETPOSANGLE_CLIENT = \
+$(SRC)/setposangle_client.$(ARCH).o	    \
+$(SRC)/update_dvo_setposangle.$(ARCH).o \
+$(SRC)/update_catalog_setposangle.$(ARCH).o \
+$(SRC)/initialize_setposangle.$(ARCH).o \
+$(SRC)/load_images_setposangle.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o	    \
+$(SRC)/Shutdown.$(ARCH).o	    \
+$(SRC)/ImageSubsetSetPosangle.$(ARCH).o
+
+$(SETPOSANGLE_CLIENT): $(INC)/setposangle.h
+$(BIN)/setposangle_client.$(ARCH): $(SETPOSANGLE_CLIENT)
+
 SETFWHM =                           \
 $(SRC)/setfwhm.$(ARCH).o	    \
Index: /trunk/Ohana/src/uniphot/include/setposangle.h
===================================================================
--- /trunk/Ohana/src/uniphot/include/setposangle.h	(revision 34749)
+++ /trunk/Ohana/src/uniphot/include/setposangle.h	(revision 34749)
@@ -0,0 +1,72 @@
+# include <ohana.h>
+# include <dvo.h>
+# include <signal.h>
+
+typedef struct {
+  unsigned int start;
+  unsigned int stop;
+  Coords coords;
+} Mosaic;
+
+typedef struct {
+  unsigned int     imageID;
+  unsigned short   NX;                   // image width
+  unsigned short   NY;                   // image height
+  e_time           tzero;                // readout time (row 0)
+  unsigned char    trate;                // scan rate (100 usec/pixel)
+  Coords           coords;
+} ImageSubset;
+
+/* global variables set in parameter file */
+# define DVO_MAX_PATH 1024
+char         ImageCat[DVO_MAX_PATH];
+char        *CATDIR;
+int          HOST_ID;
+char        *HOSTDIR;
+char        *IMAGES;
+int          VERBOSE;
+int          RESET;
+int          UPDATE;
+int          PARALLEL;
+int          PARALLEL_MANUAL;
+int          PARALLEL_SERIAL;
+
+/***** prototypes ****/
+int           main                              PROTO((int argc, char **argv));
+void          ConfigInit                        PROTO((int *argc, char **argv));
+
+void          usage_setposangle                 PROTO(());
+void          initialize_setposangle            PROTO((int argc, char **argv));
+int           args_setposangle                  PROTO((int argc, char **argv));
+
+void          usage_setposangle_client          PROTO(());
+void          initialize_setposangle_client     PROTO((int argc, char **argv));
+int           args_setposangle_client           PROTO((int argc, char **argv));
+
+// int           update_dvo_setposangle_client  PROTO((ImageSubset *image, off_t Nimage, FlatCorrectionTable *flatcorr));
+
+ImageSubset  *ImageSubsetLoad                   PROTO((char *filename, off_t *nimage));
+int           ImageSubsetSave                   PROTO((char *filename, ImageSubset *image, off_t Nimage));
+Image        *ImagesFromSubset                  PROTO((ImageSubset *subset, off_t N));
+ImageSubset  *ImagesToSubset                    PROTO((Image *image, off_t N));
+
+void          lock_image_db                     PROTO((FITS_DB *db, char *filename));
+void          unlock_image_db                   PROTO((FITS_DB *db));
+void          create_image_db                   PROTO((FITS_DB *db));
+void          set_db                            PROTO((FITS_DB *in));
+int           Shutdown                          PROTO((char *format, ...) OHANA_FORMAT(printf, 1, 2) );
+void          TrapSignal                        PROTO((int sig));
+void          SetProtect                        PROTO((int mode));
+int           SetSignals                        PROTO((void));
+
+Image        *load_images_setposangle           PROTO((FITS_DB *db, off_t *Nimage));
+int           update_dvo_setposangle            PROTO((ImageSubset *image, off_t Nimage));
+int           update_dvo_setposangle_parallel   PROTO((SkyTable *sky, ImageSubset *image, off_t Nimage));
+
+void          update_catalog_setposangle        PROTO((Catalog *catalog, ImageSubset *image, off_t *index, off_t Nimage));
+int           setposangle_local_astrometry      PROTO((float *posAngle, float *pltScale, double x, double y, Coords *mosaic, Coords *coords));
+
+off_t         getMosaicByTimes                  PROTO((unsigned int start, unsigned int stop, unsigned int *startMos, unsigned int *stopMos, off_t *indexMos));
+void          sort_mosaic_times                 PROTO((unsigned int *S, unsigned int *E, off_t *I, off_t N));
+void          initMosaics                       PROTO((ImageSubset *image, off_t Nimage));
+Mosaic       *getMosaicForImage                 PROTO((off_t im));
Index: /trunk/Ohana/src/uniphot/src/ImageSubsetSetPosangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/ImageSubsetSetPosangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/ImageSubsetSetPosangle.c	(revision 34749)
@@ -0,0 +1,327 @@
+# include "setposangle.h"
+
+# define GET_COLUMN(OUT,NAME,TYPE) \
+  TYPE *OUT = gfits_get_bintable_column_data (&theader, &ftable, NAME, type, &Nrow, &Ncol); \
+  myAssert (!strcmp(type, #TYPE), "wrong column type");
+
+ImageSubset *ImageSubsetLoad(char *filename, off_t *nimage) {
+
+  int Ncol;
+  off_t i, j, k;
+  off_t Nrow;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  *nimage = 0;
+  ImageSubset *image = NULL;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) {
+    fclose (f);
+    return NULL;
+  }
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
+    fclose (f);
+    return NULL;
+  }
+  fclose (f);
+
+  // a bit annoying : we read the entire block of data (180M), then extract the columns,
+  // then set the image structure values.  this means I need 3 copies in memory at some
+  // point.  ugh.
+
+  char type[16];
+
+  GET_COLUMN (imageID,    "IMAGE_ID",   int);
+  GET_COLUMN (tzero,      "TZERO",      float);
+  GET_COLUMN (trate,      "TRATE",      float);
+  GET_COLUMN (NX,         "NX",         int);
+  GET_COLUMN (NY,         "NY",         int);
+  GET_COLUMN (crval1,     "CRVAL1",     double);
+  GET_COLUMN (crval2,     "CRVAL2",     double);
+  GET_COLUMN (crpix1,     "CRPIX1",     float);
+  GET_COLUMN (crpix2,     "CRPIX2",     float);
+  GET_COLUMN (cdelt1,     "CDELT1",     float);
+  GET_COLUMN (cdelt2,     "CDELT2",     float);
+  GET_COLUMN (pc1_1,      "PC1_1",      float);
+  GET_COLUMN (pc1_2,      "PC1_2",      float);
+  GET_COLUMN (pc2_1,      "PC2_1",      float);
+  GET_COLUMN (pc2_2,      "PC2_2",      float);
+  GET_COLUMN (polyterms,  "POLYTERMS",  float);
+  GET_COLUMN (ctype,      "CTYPE",      char);
+  GET_COLUMN (Npolyterms, "NPOLYTERMS", int);
+
+  // GET_COLUMN (polyterms,  "POLYTERMS",  float[7][2]);
+  // GET_COLUMN (ctype,      "CTYPE",      char[15]);
+
+  // XXX free the fits table data here 
+
+  ALLOCATE (image, ImageSubset, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    image[i].imageID           = imageID[i];
+    image[i].tzero             = tzero[i];
+    image[i].trate             = trate[i];
+    image[i].NX                = NX[i];
+    image[i].NY                = NY[i];
+    image[i].coords.crval1     = crval1[i];
+    image[i].coords.crval2     = crval2[i];
+    image[i].coords.crpix1     = crpix1[i];
+    image[i].coords.crpix2     = crpix2[i];
+    image[i].coords.cdelt1     = cdelt1[i];
+    image[i].coords.cdelt2     = cdelt2[i];
+    image[i].coords.pc1_1      = pc1_1[i];
+    image[i].coords.pc1_2      = pc1_2[i];
+    image[i].coords.pc2_1      = pc2_1[i];
+    image[i].coords.pc2_2      = pc2_2[i];
+    for (j = 0; j < 7; j++) {
+      for (k = 0; k < 2; k++) {
+	image[i].coords.polyterms[j][k] = polyterms[i*14 + j*2 + k];
+      }
+    }
+    for (j = 0; j < 15; j++) {
+      image[i].coords.ctype[j] = ctype[i*15 + j];
+    }
+    image[i].coords.Npolyterms = Npolyterms[i];
+  }
+  fprintf (stderr, "loaded data for %lld images\n", (long long) Nrow);
+
+  free (imageID);
+  free (tzero);
+  free (trate);
+  free (NX);
+  free (NY);
+  free (crval1);
+  free (crval2);
+  free (crpix1);
+  free (crpix2);
+  free (cdelt1);
+  free (cdelt2);
+  free (pc1_1);
+  free (pc1_2);
+  free (pc2_1);
+  free (pc2_2);
+  free (polyterms);
+  free (ctype);
+  free (Npolyterms);
+
+  *nimage = Nrow;
+  return image;
+}
+
+int ImageSubsetSave(char *filename, ImageSubset *image, off_t Nimage) {
+
+  off_t i, j, k;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  gfits_init_header (&header);
+  header.extend = TRUE;
+  gfits_create_header (&header);
+  gfits_create_matrix (&header, &matrix);
+
+  gfits_create_table_header (&theader, "BINTABLE", "IMAGE_SUBSET");
+
+  // an unsigned int needs to have bzero of 0x8000
+  gfits_define_bintable_column (&theader, "J",   "IMAGE_ID",   "image ID", NULL, 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "E",   "TZERO",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E",   "TRATE",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J",   "NX",         "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J",   "NY",         "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", 	 "CRVAL1",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", 	 "CRVAL2",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "CRPIX1",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "CRPIX2",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "CDELT1",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "CDELT2",     "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "PC1_1",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "PC1_2",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "PC2_1",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", 	 "PC2_2",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "14E", "POLYTERMS",  "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "15A", "CTYPE",      "tmp", 	   "mp", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "J",   "NPOLYTERMS", "tmp", 	   "mp", 1.0, 0.0);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  double *crval1, *crval2;
+  float *tzero, *trate, *crpix1, *crpix2, *cdelt1, *cdelt2, *pc1_1, *pc1_2, *pc2_1, *pc2_2, *polyterms;
+  unsigned int *imageID;
+  int *NX, *NY, *Npolyterms;
+  char *ctype;
+
+  // create intermediate storage arrays
+  ALLOCATE (imageID,    unsigned int, Nimage);
+  ALLOCATE (tzero,      float,        Nimage);
+  ALLOCATE (trate,      float,        Nimage);
+  ALLOCATE (NX,         int,          Nimage);
+  ALLOCATE (NY,         int,          Nimage);
+  ALLOCATE (crval1,     double,       Nimage);
+  ALLOCATE (crval2,     double,       Nimage);
+  ALLOCATE (crpix1,     float,        Nimage);
+  ALLOCATE (crpix2,     float,        Nimage);
+  ALLOCATE (cdelt1,     float,        Nimage);
+  ALLOCATE (cdelt2,     float,        Nimage);
+  ALLOCATE (pc1_1,      float,        Nimage);
+  ALLOCATE (pc1_2,      float,        Nimage);
+  ALLOCATE (pc2_1,      float,        Nimage);
+  ALLOCATE (pc2_2,      float,        Nimage);
+  ALLOCATE (polyterms,  float,     14*Nimage);
+  ALLOCATE (ctype,      char,      15*Nimage);
+  ALLOCATE (Npolyterms, int,          Nimage);
+
+  // assign the storage arrays
+  for (i = 0; i < Nimage; i++) {
+    imageID[i] = image[i].imageID       ;
+    tzero[i]   = image[i].tzero         ;  
+    trate[i]   = image[i].trate         ;  
+    NX[i]      = image[i].NX            ;	    
+    NY[i]      = image[i].NY            ;	    
+    crval1[i]  = image[i].coords.crval1 ; 
+    crval2[i]  = image[i].coords.crval2 ; 
+    crpix1[i]  = image[i].coords.crpix1 ; 
+    crpix2[i]  = image[i].coords.crpix2 ; 
+    cdelt1[i]  = image[i].coords.cdelt1 ; 
+    cdelt2[i]  = image[i].coords.cdelt2 ; 
+    pc1_1[i]   = image[i].coords.pc1_1  ;  
+    pc1_2[i]   = image[i].coords.pc1_2  ;  
+    pc2_1[i]   = image[i].coords.pc2_1  ;  
+    pc2_2[i]   = image[i].coords.pc2_2  ;  
+    for (j = 0; j < 7; j++) {
+      for (k = 0; k < 2; k++) {
+        polyterms[i*14 + j*2 + k] = image[i].coords.polyterms[j][k];
+      }
+    }
+    for (j = 0; j < 15; j++) {
+      ctype[i*15 + j] = image[i].coords.ctype[j];
+    }
+    Npolyterms[i] = image[i].coords.Npolyterms;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "IMAGE_ID",   imageID,    Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "TZERO",      tzero,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "TRATE",      trate,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "NX",         NX,         Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "NY",         NY,         Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CRVAL1",     crval1,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CRVAL2",     crval2,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CRPIX1",     crpix1,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CRPIX2",     crpix2,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CDELT1",     cdelt1,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CDELT2",     cdelt2,     Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "PC1_1",      pc1_1,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "PC1_2",      pc1_2,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "PC2_1",      pc2_1,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "PC2_2",      pc2_2,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "POLYTERMS",  polyterms,  Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "CTYPE",      ctype,      Nimage);
+  gfits_set_bintable_column (&theader, &ftable, "NPOLYTERMS", Npolyterms, Nimage);
+
+  free (imageID   );
+  free (tzero     );
+  free (trate     );
+  free (NX        );
+  free (NY        );
+  free (crval1    );
+  free (crval2    );
+  free (crpix1    );
+  free (crpix2    );
+  free (cdelt1    );
+  free (cdelt2    );
+  free (pc1_1     );
+  free (pc1_2     );
+  free (pc2_1     );
+  free (pc2_2     );
+  free (polyterms );
+  free (ctype     );
+  free (Npolyterms);
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file for output %s\n", filename);
+    return FALSE;
+  }
+
+  gfits_fwrite_header  (f, &header);
+  gfits_fwrite_matrix  (f, &matrix);
+  gfits_fwrite_Theader (f, &theader);
+  gfits_fwrite_table  (f, &ftable);
+
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  fclose (f);
+  fflush (f);
+
+  return TRUE;
+}
+
+Image *ImagesFromSubset (ImageSubset *subset, off_t N) {
+
+  off_t i;
+
+  // we have been given an ImageSubset array, containing a reduced set of image fields
+  // create full a Image array and save the needed values
+  Image *image = NULL;
+  ALLOCATE (image, Image, N);
+  for (i = 0; i < N; i++) {
+    image[i].imageID       = subset[i].imageID;
+    image[i].NX            = subset[i].NX     ;
+    image[i].NY            = subset[i].NY     ;
+    image[i].tzero         = subset[i].tzero  ;
+    image[i].trate         = subset[i].trate  ;
+    image[i].coords        = subset[i].coords ;
+  }
+  return image;
+}
+
+ImageSubset *ImagesToSubset (Image *image, off_t N) {
+
+  off_t i;
+
+  // we have been given an ImageSubset array, containing a reduced set of image fields
+  // create full a Image array and save the needed values
+  ImageSubset *subset = NULL;
+  ALLOCATE (subset, ImageSubset, N);
+
+  for (i = 0; i < N; i++) {
+    subset[i].imageID = image[i].imageID;
+    subset[i].NX      = image[i].NX     ;
+    subset[i].NY      = image[i].NY     ;
+    subset[i].tzero   = image[i].tzero  ;
+    subset[i].trate   = image[i].trate  ;
+    subset[i].coords  = image[i].coords ;
+  }
+  return subset;
+}
+
Index: /trunk/Ohana/src/uniphot/src/initialize_setphot.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/initialize_setphot.c	(revision 34748)
+++ /trunk/Ohana/src/uniphot/src/initialize_setphot.c	(revision 34749)
@@ -21,5 +21,5 @@
   // load the photcode table
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, TRUE)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
     fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
Index: /trunk/Ohana/src/uniphot/src/initialize_setphot_client.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/initialize_setphot_client.c	(revision 34748)
+++ /trunk/Ohana/src/uniphot/src/initialize_setphot_client.c	(revision 34749)
@@ -17,5 +17,5 @@
   // load the photcode table : XXX needed?
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, TRUE)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
     fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
     exit (1);
Index: /trunk/Ohana/src/uniphot/src/initialize_setposangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/initialize_setposangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/initialize_setposangle.c	(revision 34749)
@@ -0,0 +1,221 @@
+# include "setposangle.h"
+
+void usage_setposangle () {
+    fprintf (stderr, "USAGE: setposangle [options]\n");
+    fprintf (stderr, "  options:\n");
+    fprintf (stderr, "    -v : verbose mode\n");
+    fprintf (stderr, "    -update : actually write results to detections tables\n");
+    fprintf (stderr, "    Note that the dvo db can be specified by -D CATDIR (directory)\n");
+    exit (2);
+}
+
+void initialize_setposangle (int argc, char **argv) {
+
+  int N;
+  struct stat statbuffer;
+  char CatdirPhotcodeFile[256];
+
+  if ((N = get_argument (argc, argv, "-h"))) usage_setposangle();
+  if ((N = get_argument (argc, argv, "-help"))) usage_setposangle();
+  if ((N = get_argument (argc, argv, "--h"))) usage_setposangle();
+  if ((N = get_argument (argc, argv, "--help"))) usage_setposangle();
+
+  /* are these set correctly? */
+  ConfigInit (&argc, argv);
+  args_setposangle (argc, argv);
+
+  if (stat (CATDIR, &statbuffer)) {
+    fprintf (stderr, "error accessing dvo database directory '%s'\n", CATDIR);
+    exit (1);
+  }
+
+  // load the photcode table
+  sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
+    exit (1);
+  }
+}
+
+int args_setposangle (int argc, char **argv) {
+
+  int N;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  // XXX I want to avoid running this on all data all the time
+  // some options: gpc1 only (hardwired), require photcodes (fairly tedious),
+  // exclude some photcodes?
+  // XXX for now, hardwire gpc1 photcodes
+
+  PARALLEL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel"))) {
+    PARALLEL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the remote jobs and waiting for completion,
+  // setposangle will simply list the remote command and wait for the user to signal completion
+  PARALLEL_MANUAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-manual"))) {
+    PARALLEL = TRUE; // -parallel-manual implies -parallel
+    PARALLEL_MANUAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the setposangle_client jobs remotely, they are 
+  // run in serial via 'system'
+  PARALLEL_SERIAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-serial"))) {
+    if (PARALLEL_MANUAL) {
+      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
+      exit (1);
+    }
+    PARALLEL = TRUE; // -parallel-serial implies -parallel
+    PARALLEL_SERIAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  UPDATE = FALSE;
+  if ((N = get_argument (argc, argv, "-update"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE = TRUE;
+  }
+
+  if (argc != 1) usage_setposangle();
+
+  return (TRUE);
+}
+
+void usage_setposangle_client () {
+  fprintf (stderr, "USAGE: setposangle_client -hostID (hostID) -catdir (catdir) -hostdir (hostdir) -images (images) [options]\n");
+  fprintf (stderr, "  options:\n");
+  fprintf (stderr, "    -v : verbose mode\n");
+  fprintf (stderr, "    -update : actually write results to detections tables\n");
+  exit (2);
+}
+
+void initialize_setposangle_client (int argc, char **argv) {
+
+  int N;
+  struct stat statbuffer;
+  char CatdirPhotcodeFile[256];
+
+  if ((N = get_argument (argc, argv, "-h"))) usage_setposangle_client();
+  if ((N = get_argument (argc, argv, "-help"))) usage_setposangle_client();
+  if ((N = get_argument (argc, argv, "--h"))) usage_setposangle_client();
+  if ((N = get_argument (argc, argv, "--help"))) usage_setposangle_client();
+
+  SetZeroPoint (25.0); // XXX is this needed?
+  args_setposangle_client (argc, argv);
+
+  if (stat (CATDIR, &statbuffer)) {
+    fprintf (stderr, "error accessing dvo database directory '%s'\n", CATDIR);
+    exit (1);
+  }
+
+  // load the photcode table : XXX needed?
+  sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
+  if (!LoadPhotcodes (CatdirPhotcodeFile, NULL, FALSE)) {
+    fprintf (stderr, "error loading photcode table %s\n", CatdirPhotcodeFile);
+    exit (1);
+  }
+}
+
+int args_setposangle_client (int argc, char **argv) {
+
+  int N;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  UPDATE = FALSE;
+  if ((N = get_argument (argc, argv, "-update"))) {
+    remove_argument (N, &argc, argv);
+    UPDATE = TRUE;
+  }
+
+  HOST_ID = 0;
+  if ((N = get_argument (argc, argv, "-hostID"))) {
+    remove_argument (N, &argc, argv);
+    HOST_ID = atoi (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!HOST_ID) usage_setposangle_client();
+
+  HOSTDIR = NULL;
+  if ((N = get_argument (argc, argv, "-hostdir"))) {
+    remove_argument (N, &argc, argv);
+    HOSTDIR = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!HOSTDIR) usage_setposangle_client();
+
+  if ((N = get_argument (argc, argv, "-catdir"))) {
+    remove_argument (N, &argc, argv);
+    CATDIR = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!CATDIR) usage_setposangle_client();
+
+  IMAGES = NULL;
+  if ((N = get_argument (argc, argv, "-images"))) {
+    remove_argument (N, &argc, argv);
+    IMAGES = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!IMAGES) usage_setposangle_client();
+
+  if (argc != 1) usage_setposangle_client();
+  return (TRUE);
+}
+
+void GetConfig (char *config, char *field, char *format, int N, void *ptr);
+
+void ConfigInit (int *argc, char **argv) {
+
+  double ZERO_POINT;
+  char  *config, *file;
+
+  /*** load configuration info ***/
+  file = SelectConfigFile (argc, argv, "ptolemy");
+  config = LoadConfigFile (file);
+  if (config == (char *) NULL) {
+    fprintf (stderr, "ERROR: can't find configuration file %s\n", file);
+    if (file != (char *) NULL) free (file);
+    exit (0);
+  }
+  if (VERBOSE) fprintf (stderr, "loaded config file: %s\n", file);
+
+  // force CATDIR to be absolute (so parallel mode will work)
+  char *tmpcatdir = NULL;
+  ALLOCATE (tmpcatdir, char, DVO_MAX_PATH);
+  GetConfig (config, "CATDIR",                 "%s",  0, tmpcatdir);
+  CATDIR = abspath (tmpcatdir, DVO_MAX_PATH);
+  free (tmpcatdir);
+
+  sprintf (ImageCat, "%s/Images.dat", CATDIR);
+
+  ScanConfig (config, "ZERO_PT",                "%lf", 0, &ZERO_POINT);
+  SetZeroPoint (ZERO_POINT);
+
+  free (config);
+  free (file);
+}
+
+void GetConfig (char *config, char *field, char *format, int N, void *ptr) {
+
+  char *status;
+
+  status = ScanConfig (config, field, format, N, ptr);
+  if (status == NULL) {
+    fprintf (stderr, "error in config, cannot find %s\n", field);
+    exit (1);
+  }
+  return;
+}
Index: /trunk/Ohana/src/uniphot/src/load_images_setposangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/load_images_setposangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/load_images_setposangle.c	(revision 34749)
@@ -0,0 +1,174 @@
+# include "setposangle.h"
+
+// array of mosaic definition structures
+static off_t   Nmosaic;
+static Mosaic *mosaic;
+
+// list of mosaic associated with each image  
+static off_t    Nmosaic_for_images; // number of images (for off_ternal checks)
+static off_t    *mosaic_for_images; // array of: image -> mosaic
+
+Image *load_images_setposangle (FITS_DB *db, off_t *Nimage) {
+
+  Image *image;
+
+  if (VERBOSE) fprintf (stderr, "finding images\n");
+
+  /* read entire db table */
+  if (!dvo_image_load (db, VERBOSE, FALSE)) Shutdown ("can't read image catalog %s", db[0].filename);
+
+  /* use a vtable to keep the images to be calibrated */
+  image = gfits_table_get_Image (&db[0].ftable, Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
+
+  fprintf (stderr, "loaded "OFF_T_FMT" images\n", *Nimage);
+
+  return (image);
+}
+
+// I need an index to go from image to associated mosaic (if existant)
+// This code is copied from relastro/src/MosaicOps.c
+
+off_t getMosaicByTimes (unsigned int start, unsigned int stop, unsigned int *startMos, unsigned int *stopMos, off_t *indexMos) {
+
+  // use bisection to find the overlapping mosaic
+
+  off_t Nlo, Nhi, N;
+
+  // find the last mosaic before start
+  Nlo = 0; Nhi = Nmosaic;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (startMos[N] < start) {
+      Nlo = MAX(N, 0);
+    } else {
+      Nhi = MIN(N + 1, Nmosaic);
+    }
+  }
+
+  // check for the matched mosaic starting from Nlo 
+  // we may have to go much beyond Nlo since stop is not sorted
+  // can we use a sorted version of stop to check when we are beyond the valid range??
+  for (N = Nlo; N < Nmosaic; N++) { 
+    if (stop  < stopMos[N]) continue;
+    if (start > startMos[N])  continue;
+    if (stop  < startMos[N]) return (-1);
+    return (indexMos[N]);
+  }
+
+  return (-1);
+}
+
+// sort two times vectors and an index by first time vector
+void sort_mosaic_times (unsigned int *S, unsigned int *E, off_t *I, off_t N) {
+
+# define SWAPFUNC(A,B){ unsigned int tmp_t; off_t tmp_i; \
+  tmp_t = S[A]; S[A] = S[B]; S[B] = tmp_t; \
+  tmp_t = E[A]; E[A] = E[B]; E[B] = tmp_t; \
+  tmp_i = I[A]; I[A] = I[B]; I[B] = tmp_i; \
+}
+# define COMPARE(A,B)(S[A] < S[B])
+
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+
+}
+
+// use the time to make the match, but use bracketing to make it faster:
+
+// find mosaic frames (unique time periods & photcode name matches mosaic) 
+void initMosaics (ImageSubset *image, off_t Nimage) {
+
+  off_t i, Nmos, NMOSAIC;
+  unsigned int start, stop;
+
+  unsigned int *startMos, *stopMos;
+  off_t *indexMos;
+
+  Nmosaic = 0;
+  NMOSAIC = 10;
+  ALLOCATE (mosaic, Mosaic, NMOSAIC);
+
+  ALLOCATE (startMos, unsigned int, NMOSAIC);
+  ALLOCATE (stopMos, unsigned int, NMOSAIC);
+  ALLOCATE (indexMos, off_t, NMOSAIC);
+
+  /* find the mosaic images (coords.ctype = DIS); generate list of unique mosaics */
+  for (i = 0; i < Nimage; i++) {
+    if (strcmp(&image[i].coords.ctype[4], "-DIS")) continue;
+
+    /* set image time range */
+    start = image[i].tzero - MAX(0.01*image[i].trate*image[i].NY, 1);
+    stop  = image[i].tzero + MAX(1.01*image[i].trate*image[i].NY, 1);
+
+    /* a new mosaic, define ranges */
+    mosaic[Nmosaic].start = start;
+    mosaic[Nmosaic].stop  = stop;
+    mosaic[Nmosaic].coords = image[i].coords;
+
+    startMos[Nmosaic] = start;
+    stopMos[Nmosaic] = stop;
+    indexMos[Nmosaic] = Nmosaic;
+
+    Nmosaic ++;
+    if (Nmosaic == NMOSAIC) {
+      NMOSAIC += 10;
+      REALLOCATE (mosaic, Mosaic, NMOSAIC);
+      REALLOCATE (startMos, unsigned int, NMOSAIC);
+      REALLOCATE (stopMos, unsigned int, NMOSAIC);
+      REALLOCATE (indexMos, off_t, NMOSAIC);
+    }
+  }
+
+  // sort the index, start, and stop by the start times:
+  sort_mosaic_times (startMos, stopMos, indexMos, Nmosaic);
+  
+  // array to store image->mosaic index
+  Nmosaic_for_images = Nimage;
+  ALLOCATE (mosaic_for_images, off_t, Nmosaic_for_images);
+
+  /* now assign the WRP images to these mosaics */
+  for (i = 0; i < Nimage; i++) {
+    mosaic_for_images[i] = -1; // default value for no mosaic found
+
+    if (strcmp(&image[i].coords.ctype[4], "-WRP")) continue;
+
+    /* set image time range */
+    start = image[i].tzero - MAX(0.01*image[i].trate*image[i].NY, 1);
+    stop  = image[i].tzero + MAX(1.01*image[i].trate*image[i].NY, 1);
+
+    Nmos = getMosaicByTimes (start, stop, startMos, stopMos, indexMos);
+    if (Nmos == -1) {
+      fprintf (stderr, "cannot match mosaic for %d (ID = %d)\n", (int) i, (int) image[i].imageID);
+      continue;
+    }
+
+    // mosaic corresponding to this image
+    mosaic_for_images[i] = Nmos;
+  }
+
+  free (startMos);
+  free (stopMos);
+  free (indexMos);
+  return;
+}
+
+Mosaic *getMosaicForImage (off_t im) {
+
+  off_t mos;
+
+  if (im < 0) abort();
+  if (im >= Nmosaic_for_images) abort();
+
+  // search for the mosaic that 
+  mos = mosaic_for_images[im];
+  if (mos < 0) return NULL;
+
+  return &mosaic[mos];
+}
+
Index: /trunk/Ohana/src/uniphot/src/setposangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/setposangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/setposangle.c	(revision 34749)
@@ -0,0 +1,36 @@
+# include "setposangle.h"
+
+int main (int argc, char **argv) {
+
+  off_t Nimage;
+  int status;
+  FITS_DB db;
+
+  /* get configuration info, args, lockfile */
+  initialize_setposangle (argc, argv);
+
+  set_db (&db);
+  status = dvo_image_lock (&db, ImageCat, 60.0, (UPDATE ? LCK_XCLD : LCK_SOFT));
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", db.filename);
+  if (db.dbstate == LCK_EMPTY) Shutdown ("ERROR: No images in catalog %s (1)", db.filename);
+
+  // load images (images are not modified, but we need the astrometry transformations
+  Image *image  = load_images_setposangle (&db, &Nimage);
+  dvo_image_unlock (&db); 
+  
+  // the imageSubset here is a reduced set of fields, not a reduced set of images
+  ImageSubset *subset = ImagesToSubset (image, Nimage);
+
+  status = update_dvo_setposangle (subset, Nimage);
+
+  if (!status) exit (1);
+  exit (0);
+}
+  
+
+/* setposangle : set the posangle & pltscale for measurements in the db
+
+   ** load images
+   ** load catalogs
+   ** update detection (& averages?)
+ */
Index: /trunk/Ohana/src/uniphot/src/setposangle_client.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/setposangle_client.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/setposangle_client.c	(revision 34749)
@@ -0,0 +1,24 @@
+# include "setposangle.h"
+
+// setposangle_client is run on a remote host and is responsible for updating the catalogs
+// owned by that host.  
+
+// setposangle_client -hostname (hostname) -catdir (catdir) -hostdir (hostdir) -images (images)
+// load the SkyTable and HostTable from (catdir) [contains the host responsibilities]
+// load the image data from (images) [contains the zp infomation to apply]
+// loop over tables from SkyTable with my host ID
+// the calling program tells the client which host they are (or host ID?); we do not actually have to run this on the real host
+
+int main (int argc, char **argv) {
+
+  // get configuration info, args, lockfile (set CATDIR, HOST_ID, HOSTDIR, IMAGES)
+  initialize_setposangle_client (argc, argv);
+
+  // load the image subset table from the specified location
+  off_t Nimage;
+  ImageSubset *subset = ImageSubsetLoad (IMAGES, &Nimage);
+
+  update_dvo_setposangle (subset, Nimage);
+
+  exit (0);
+}
Index: /trunk/Ohana/src/uniphot/src/update_catalog_setposangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/update_catalog_setposangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/update_catalog_setposangle.c	(revision 34749)
@@ -0,0 +1,95 @@
+# include "setposangle.h"
+
+void update_catalog_setposangle (Catalog *catalog, ImageSubset *image, off_t *index, off_t Nimage) {
+
+  float posAngle, pltScale;
+  off_t i, j, found;
+
+  found = 0;    
+  for (i = 0; i < catalog[0].Naverage; i++) {
+
+    off_t m = catalog[0].average[i].measureOffset;
+    for (j = 0; j < catalog[0].average[i].Nmeasure; j++, m++) {
+      off_t ID = catalog[0].measure[m].imageID;
+      if (ID <= 0) continue; // detections with imageID == 0 do not have a valid image (eg, ref photcode)
+
+      // XXX only do GPC1 data for now
+      catalog[0].measure[m].pltscale = pltScale;
+      if (catalog[0].measure[m].photcode < 10000) continue;
+      if (catalog[0].measure[m].photcode > 10600) continue;
+      
+      // index[ID] = seqN
+
+      off_t seq = index[ID];
+
+      Mosaic *mosaic = getMosaicForImage(seq);
+      Coords *coords = &image[seq].coords;
+
+      double Xccd = catalog[0].measure[m].Xccd;
+      double Yccd = catalog[0].measure[m].Yccd;
+      
+      setposangle_local_astrometry (&posAngle, &pltScale, Xccd, Yccd, &mosaic->coords, coords);
+
+      catalog[0].measure[m].posangle = ToShortDegrees(posAngle);
+      catalog[0].measure[m].pltscale = pltScale;
+      myAssert(isfinite(catalog[0].measure[m].posangle), "oops: setposangle made a nan");
+      myAssert(isfinite(catalog[0].measure[m].pltscale), "oops: setposangle made a nan");
+      found ++;
+    }
+  }
+
+  if (found) {
+    fprintf (stderr, "found "OFF_T_FMT" matches\n", found);
+  }
+}
+
+// this is basically a re-write / adaptation of pmSourceLocalAstrometry
+// posangle in degrees, plate scale in arcseconds/pixel
+int setposangle_local_astrometry (float *posAngle, float *pltScale, double x, double y, Coords *mosaic, Coords *coords) {
+
+  double Lx, Mx, Po, Qo, Px, Qx, Py, Qy;
+
+  // calculate the astrometry for the coordinate of interest
+  XY_to_LM (&Lx, &Mx, x,       y,       coords);
+  XY_to_LM (&Po, &Qo, Lx,      Mx,      mosaic);
+
+  XY_to_LM (&Lx, &Mx, x + 1.0, y,       coords);
+  XY_to_LM (&Px, &Qx, Lx,      Mx,      mosaic);
+
+  XY_to_LM (&Lx, &Mx, x,       y + 1.0, coords);
+  XY_to_LM (&Py, &Qy, Lx,      Mx,      mosaic);
+
+  // XXX units for the resulting Tangent Plane coordinates??
+
+  double dPdX = Px - Po;
+  double dPdY = Py - Po;
+
+  double dQdX = Qx - Qo;
+  double dQdY = Qy - Qo;
+
+  double pltScale_x = hypot(dPdX, dQdX);
+  double pltScale_y = hypot(dPdY, dQdY);
+  *pltScale = 3600.0*0.5*(pltScale_x + pltScale_y);
+
+  double posAngle_x, posAngle_y;
+  double crossProduct = dPdX * dQdY - dPdY * dQdX;
+  if  (crossProduct > 0.) {
+    *pltScale *= -1.0;
+    posAngle_x = atan2 (dQdX, dPdX);
+    posAngle_y = atan2 (dQdY, dPdY) - M_PI_2;
+  } else {
+    posAngle_x = atan2 (dQdX, -dPdX);
+    posAngle_y = atan2 (dQdY,  dPdY) - M_PI_2;
+  }
+
+  // with errors, these may end up on opposite sides of the M_PI boundary.  
+  if (posAngle_x - posAngle_y > M_PI) {
+    posAngle_y += 2.0 * M_PI;
+  }
+  if (posAngle_y - posAngle_x > M_PI) {
+    posAngle_x += 2.0 * M_PI;
+  }
+  *posAngle = 0.5*(posAngle_x + posAngle_y)*DEG_RAD;
+
+  return TRUE;
+}
Index: /trunk/Ohana/src/uniphot/src/update_dvo_setposangle.c
===================================================================
--- /trunk/Ohana/src/uniphot/src/update_dvo_setposangle.c	(revision 34749)
+++ /trunk/Ohana/src/uniphot/src/update_dvo_setposangle.c	(revision 34749)
@@ -0,0 +1,156 @@
+# include "setposangle.h"
+
+int update_dvo_setposangle (ImageSubset *image, off_t Nimage) {
+
+  SkyRegion UserPatch;
+  SkyTable *sky = NULL;
+  SkyList *skylist = NULL;
+  Catalog catalog;
+  off_t i, maxID, *index;
+
+  // load the current sky table (layout of all SkyRegions) 
+  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, FALSE, -1, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  if (PARALLEL && !HOST_ID) {
+    update_dvo_setposangle_parallel (sky, image, Nimage);
+    return TRUE;
+  }
+
+  // create an index for the image IDs
+  maxID = 0;
+  for (i = 0; i < Nimage; i++) {
+    maxID = MAX(maxID, image[i].imageID);
+  }
+  ALLOCATE (index, off_t, maxID + 1);
+  for (i = 0; i < maxID + 1; i++) {
+    index[i] = -1;
+  }
+  for (i = 0; i < Nimage; i++) {
+    if (!image[i].imageID) continue; // images with ID == 0 are virtual
+    index[image[i].imageID] = i;
+  }
+
+  // set up the links between images and mosaics
+  initMosaics (image, Nimage);
+
+  // determine the populated SkyRegions overlapping the requested area (default depth)
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  // update measurements for each populated catalog
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // does this host ID match the desired location for the table?
+    if (!HostTableTestHost(skylist[0].regions[i], HOST_ID)) continue;
+
+    char localFilename[1024];
+    snprintf (localFilename, 1024, "%s/%s.cpt", HOSTDIR, skylist->regions[i]->name);
+
+    // set up the basic catalog info
+    catalog.filename  = HOST_ID ? localFilename : skylist[0].filename[i];
+    catalog.catformat = DVO_FORMAT_UNDEF; // not needed since we skip empty catalogs
+    catalog.catmode   = DVO_MODE_UNDEF;	  // not needed since we skip empty catalogs
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure reading catalog %s\n", catalog.filename);
+      exit (1);
+    }
+    if (!catalog.Naves_disk) {
+      if (VERBOSE) fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    update_catalog_setposangle (&catalog, image, index, Nimage);
+
+    if (!UPDATE) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+    
+    if (VERBOSE) fprintf (stderr, "saving catalog %s\n", catalog.filename);
+    
+    dvo_catalog_save (&catalog, VERBOSE); 
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+  return (TRUE);
+}      
+
+# define DEBUG 1
+
+int update_dvo_setposangle_parallel (SkyTable *sky, ImageSubset *image, off_t Nimage) {
+
+  // write out the subset table of image information
+  char imageFile[512];
+  snprintf (imageFile, 512, "%s/Images.subset.dat", CATDIR);
+
+  if (!ImageSubsetSave (imageFile, image, Nimage)) {
+    fprintf (stderr, "failed to write image subset\n");
+    exit (1);
+  }
+
+  // now launch the setposangle_client jobs to the parallel hosts
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
+
+  int i;
+  for (i = 0; i < table->Nhosts; i++) {
+
+    // ensure that the paths are absolute path names
+    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
+    free (table->hosts[i].pathname);
+    table->hosts[i].pathname = tmppath;
+
+    char command[1024];
+    snprintf (command, 1024, "setposangle_client -hostID %d -catdir %s -hostdir %s -images %s", 
+	      table->hosts[i].hostID, CATDIR, table->hosts[i].pathname, imageFile);
+
+    fprintf (stderr, "command: %s\n", command);
+
+    char tmpline[1024];
+    if (VERBOSE)       { snprintf (tmpline, 1024, "%s -v",              command);                    strcpy (command, tmpline); }
+    if (UPDATE)        { snprintf (tmpline, 1024, "%s -update",         command); 		     strcpy (command, tmpline); }
+
+    if (PARALLEL_MANUAL) continue;
+
+    if (PARALLEL_SERIAL) {
+      int status = system (command);
+      if (status) {
+	fprintf (stderr, "ERROR running setposangle_client\n");
+	exit (2);
+      }
+    } else {
+      // launch the job on the remote machine (no handshake)
+      int errorInfo = 0;
+      int pid = rconnect ("ssh", table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
+      if (!pid) {
+	if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
+	exit (1);
+      }
+      table->hosts[i].pid = pid; // save for future reference
+    }
+  }
+
+  // wait for the remote jobs to be completed
+  if (PARALLEL_MANUAL) {
+    fprintf (stderr, "run the setposangle_client commands above.  when these are done, hit return\n");
+    getchar();
+  }
+  if (!PARALLEL_MANUAL && !PARALLEL_SERIAL) {
+    int status = HostTableWaitJobsGetIO (table, __FILE__, __LINE__, VERBOSE);
+    if (!status) return FALSE;
+  }
+
+  return (TRUE);
+}      
+
