Index: trunk/Ohana/src/addstar/Makefile
===================================================================
--- trunk/Ohana/src/addstar/Makefile	(revision 34361)
+++ trunk/Ohana/src/addstar/Makefile	(revision 34405)
@@ -47,4 +47,5 @@
 $(SRC)/SkyTableFromTychoIndex.$(ARCH).o \
 $(SRC)/addstar.$(ARCH).o \
+$(SRC)/addstar_create_ID.$(ARCH).o \
 $(SRC)/airmass.$(ARCH).o \
 $(SRC)/args.$(ARCH).o \
Index: trunk/Ohana/src/addstar/include/addstar.h
===================================================================
--- trunk/Ohana/src/addstar/include/addstar.h	(revision 34361)
+++ trunk/Ohana/src/addstar/include/addstar.h	(revision 34405)
@@ -59,5 +59,5 @@
 typedef struct sockaddr_in SockAddress;
 
-enum {ADDSTAR_MODE_NONE, ADDSTAR_MODE_IMAGE, ADDSTAR_MODE_REFLIST, ADDSTAR_MODE_REFCAT, ADDSTAR_MODE_FAKEIMAGE, ADDSTAR_MODE_RESORT};
+enum {ADDSTAR_MODE_NONE, ADDSTAR_MODE_IMAGE, ADDSTAR_MODE_REFLIST, ADDSTAR_MODE_REFCAT, ADDSTAR_MODE_FAKEIMAGE, ADDSTAR_MODE_RESORT, ADDSTAR_MODE_CREATE_ID};
 enum {NONE, SIMPLE_CMP, SIMPLE_CMF, SIMPLE_MEF, MOSAIC_CMP, MOSAIC_CMF, MOSAIC_MEF, MOSAIC_PHU, SDSS_OBJ};
 /* note: MEF implies CMF */
@@ -269,14 +269,4 @@
 int 	   NewReflist_Thread	  PROTO((int BindSocket));
 
-Stars     *Convert_SMPDATA	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DEV_0	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DEV_1	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V1	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V1_Alt	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V2	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V3	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV1	  PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV1_Alt	  PROTO((FTable *table, unsigned int *nstars));
-
 int        InitStar               PROTO((Stars *star));
 
@@ -303,4 +293,5 @@
 // this is a gnu extension?? caution!
 void *memrchr(const void *s, int c, size_t n);
+int addstar_create_ID ();
 
 /** 
Index: trunk/Ohana/src/addstar/src/MatchHeaders.c
===================================================================
--- trunk/Ohana/src/addstar/src/MatchHeaders.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/MatchHeaders.c	(revision 34405)
@@ -58,5 +58,7 @@
     if (!strcmp (exttype, "PS1_V2")) goto keep;
     if (!strcmp (exttype, "PS1_V3")) goto keep;
+    if (!strcmp (exttype, "PS1_V4")) goto keep;
     if (!strcmp (exttype, "PS1_SV1")) goto keep;
+    if (!strcmp (exttype, "PS1_SV2")) goto keep;
     continue;
 
Index: trunk/Ohana/src/addstar/src/ReadStarsFITS.c
===================================================================
--- trunk/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 34405)
@@ -1,3 +1,18 @@
 # include "addstar.h"
+
+// this is the complete list of FITS format input files the addstar knows 
+// (excluding SDSS data and reference database info, such as 2MASS)
+// NOTE: these must also be listed in MatchHeaders.c (line ~ 62)
+Stars     *Convert_SMPDATA	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_DEV_0	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_DEV_1	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_V1	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_V1_Alt	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_V2	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_V3	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_V4	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_SV1	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_SV1_Alt	  PROTO((FTable *table, unsigned int *nstars));
+Stars     *Convert_PS1_SV2	  PROTO((FTable *table, unsigned int *nstars));
 
 // given a file with the pointer at the start of the table block and the 
@@ -54,6 +69,12 @@
     stars = Convert_PS1_V3 (&table, &Nstars);
   }
+  if (!strcmp (type, "PS1_V4")) {
+    stars = Convert_PS1_V4 (&table, &Nstars);
+  }
   if (!strcmp (type, "PS1_SV1")) {
     stars = Convert_PS1_SV1 (&table, &Nstars);
+  }
+  if (!strcmp (type, "PS1_SV2")) {
+    stars = Convert_PS1_SV2 (&table, &Nstars);
   }
   if (stars == NULL) {
@@ -120,5 +141,5 @@
 
     stars[i].measure.psfChisq 	= NAN;	     // not provided by SMPDATA:
-    stars[i].measure.psfQual  	= NAN;	     // not provided by SMPDATA:
+    stars[i].measure.psfQF  	= NAN;	     // not provided by SMPDATA:
     stars[i].measure.psfNdof    = NAN_S_INT; // not provided by SMPDATA:
     stars[i].measure.psfNpix    = NAN_S_INT; // not provided by SMPDATA:
@@ -189,5 +210,5 @@
 
     stars[i].measure.psfChisq 	= ps1data[i].psfChisq;
-    stars[i].measure.psfQual  	= ps1data[i].psfQual;
+    stars[i].measure.psfQF  	= ps1data[i].psfQF;
     stars[i].measure.psfNdof    = NAN_S_INT; // not provided by PS1_DEV_0:
     stars[i].measure.psfNpix    = NAN_S_INT; // not provided by PS1_DEV_0:
@@ -261,5 +282,5 @@
 
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = NAN_S_INT; // not provided by PS1_DEV_1:
     stars[i].measure.psfNpix    = NAN_S_INT; // not provided by PS1_DEV_1:
@@ -345,5 +366,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -430,5 +451,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -507,5 +528,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -584,5 +605,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -616,5 +637,5 @@
 }
 
-Stars *Convert_PS1_SV1 (FTable *table, unsigned int *nstars) {
+Stars *Convert_PS1_V4 (FTable *table, unsigned int *nstars) {
 
   off_t Nstars; 
@@ -622,12 +643,7 @@
   double ZeroPt;
   Stars *stars;
-  CMF_PS1_SV1 *ps1data;
-
-  if (table[0].header[0].Naxis[0] == 196) {
-    stars = Convert_PS1_SV1_Alt (table, nstars);
-    return (stars);
-  }
-
-  ps1data = gfits_table_get_CMF_PS1_SV1 (table, &Nstars, NULL);
+  CMF_PS1_V4 *ps1data;
+
+  ps1data = gfits_table_get_CMF_PS1_V4 (table, &Nstars, NULL);
   if (!ps1data) {
     fprintf (stderr, "skipping inconsistent entry\n");
@@ -658,5 +674,5 @@
     stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
     stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
-
+                        
     // these fluxes are converted from counts to counts/sec in FilterStars.c
     stars[i].measure.FluxPSF    = ps1data[i].Flux;
@@ -669,5 +685,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -689,6 +705,9 @@
 
     // the Average fields and the following Measure fields are set in FilterStars after
-    // the image metadata is in hand:  dR, dD, Mcal, dt, airmass, az, t, imageID, extID, 
-    // averef is set in find_matches, dbFlags is zero on ingest.
+    // the image metadata is in hand:  dR, dD, Mcal, dt, airmass, az, t, imageID, extID.
+
+    // averef is set in find_matches
+
+    // dbFlags is zero on ingest.
 
     // the following fields are currently not being set anywhere: t_msec
@@ -698,5 +717,5 @@
 }
 
-Stars *Convert_PS1_SV1_Alt (FTable *table, unsigned int *nstars) {
+Stars *Convert_PS1_SV1 (FTable *table, unsigned int *nstars) {
 
   off_t Nstars; 
@@ -706,7 +725,10 @@
   CMF_PS1_SV1 *ps1data;
 
-  // some test output files were produced called CMF_PS1_SV1 but with mismatch byte boundaries
-
-  ps1data = gfits_table_get_CMF_PS1_SV1_Alt (table, &Nstars, NULL);
+  if (table[0].header[0].Naxis[0] == 196) {
+    stars = Convert_PS1_SV1_Alt (table, nstars);
+    return (stars);
+  }
+
+  ps1data = gfits_table_get_CMF_PS1_SV1 (table, &Nstars, NULL);
   if (!ps1data) {
     fprintf (stderr, "skipping inconsistent entry\n");
@@ -748,5 +770,5 @@
                         
     stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQual    = ps1data[i].psfQual;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
     stars[i].measure.psfNdof    = ps1data[i].psfNdof;
     stars[i].measure.psfNpix    = ps1data[i].psfNpix;
@@ -777,2 +799,159 @@
 }
 
+Stars *Convert_PS1_SV1_Alt (FTable *table, unsigned int *nstars) {
+
+  off_t Nstars; 
+  unsigned int i;
+  double ZeroPt;
+  Stars *stars;
+  CMF_PS1_SV1 *ps1data;
+
+  // some test output files were produced called CMF_PS1_SV1 but with mismatch byte boundaries
+
+  ps1data = gfits_table_get_CMF_PS1_SV1_Alt (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
+  ZeroPt = GetZeroPoint();
+
+  ALLOCATE (stars, Stars, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    InitStar (&stars[i]);
+    stars[i].measure.Xccd       = ps1data[i].X;
+    stars[i].measure.Yccd       = ps1data[i].Y;
+    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
+    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
+
+    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
+    stars[i].measure.pltscale   = ps1data[i].pltscale;
+
+    if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
+      stars[i].measure.M      = NAN;
+    } else {
+      stars[i].measure.M      = ps1data[i].M + ZeroPt;
+    }
+    stars[i].measure.dM         = ps1data[i].dM;
+    stars[i].measure.dMcal      = ps1data[i].dMcal;
+    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
+                        
+    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+
+    // these fluxes are converted from counts to counts/sec in FilterStars.c
+    stars[i].measure.FluxPSF    = ps1data[i].Flux;
+    stars[i].measure.dFluxPSF   = ps1data[i].dFlux;
+    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
+    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
+
+    stars[i].measure.Sky        = ps1data[i].sky;
+    stars[i].measure.dSky       = ps1data[i].dSky;
+                        
+    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
+    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
+    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
+    stars[i].measure.crNsigma   = ps1data[i].crNsigma;
+    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
+
+    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
+    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
+    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
+
+    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
+    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
+    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    stars[i].measure.photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    stars[i].measure.detID      = ps1data[i].detID; 
+
+    // the Average fields and the following Measure fields are set in FilterStars after
+    // the image metadata is in hand:  dR, dD, Mcal, dt, airmass, az, t, imageID, extID, 
+    // averef is set in find_matches, dbFlags is zero on ingest.
+
+    // the following fields are currently not being set anywhere: t_msec
+  }    
+  *nstars = Nstars;
+  return (stars);
+}
+
+Stars *Convert_PS1_SV2 (FTable *table, unsigned int *nstars) {
+
+  off_t Nstars; 
+  unsigned int i;
+  double ZeroPt;
+  Stars *stars;
+  CMF_PS1_SV2 *ps1data;
+
+  ps1data = gfits_table_get_CMF_PS1_SV2 (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
+  ZeroPt = GetZeroPoint();
+
+  ALLOCATE (stars, Stars, Nstars);
+  for (i = 0; i < Nstars; i++) {
+    InitStar (&stars[i]);
+    stars[i].measure.Xccd       = ps1data[i].X;
+    stars[i].measure.Yccd       = ps1data[i].Y;
+    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
+    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
+
+    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
+    stars[i].measure.pltscale   = ps1data[i].pltscale;
+
+    if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
+      stars[i].measure.M      = NAN;
+    } else {
+      stars[i].measure.M      = ps1data[i].M + ZeroPt;
+    }
+    stars[i].measure.dM         = ps1data[i].dM;
+    stars[i].measure.dMcal      = ps1data[i].dMcal;
+    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
+                        
+    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+
+    // these fluxes are converted from counts to counts/sec in FilterStars.c
+    stars[i].measure.FluxPSF    = ps1data[i].Flux;
+    stars[i].measure.dFluxPSF   = ps1data[i].dFlux;
+    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
+    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
+
+    stars[i].measure.Sky        = ps1data[i].sky;
+    stars[i].measure.dSky       = ps1data[i].dSky;
+                        
+    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
+    stars[i].measure.psfQF      = ps1data[i].psfQF;
+    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
+    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
+    stars[i].measure.crNsigma   = ps1data[i].crNsigma;
+    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
+
+    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
+    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
+    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
+
+    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
+    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
+    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    stars[i].measure.photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    stars[i].measure.detID      = ps1data[i].detID; 
+
+    // the Average fields and the following Measure fields are set in FilterStars after
+    // the image metadata is in hand:  dR, dD, Mcal, dt, airmass, az, t, imageID, extID, 
+    // averef is set in find_matches, dbFlags is zero on ingest.
+
+    // the following fields are currently not being set anywhere: t_msec
+  }    
+  *nstars = Nstars;
+  return (stars);
+}
+
+
Index: trunk/Ohana/src/addstar/src/SEDfit.c
===================================================================
--- trunk/Ohana/src/addstar/src/SEDfit.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/SEDfit.c	(revision 34405)
@@ -147,27 +147,10 @@
     // construct an average object for this object
     // XXX for now, the output objects will have limited astrometric interpretation...
+    dvo_average_init (&outcat[0].average[Nave]);
     outcat[0].average[Nave].R         = incat[0].average[i].R;
     outcat[0].average[Nave].D         = incat[0].average[i].D;
-    outcat[0].average[Nave].dR    = 0;
-    outcat[0].average[Nave].dD    = 0;
-    outcat[0].average[Nave].uR    = 0;
-    outcat[0].average[Nave].uD    = 0;
-    outcat[0].average[Nave].duR   = 0;
-    outcat[0].average[Nave].duD   = 0;
-    outcat[0].average[Nave].P     = 0;
-    outcat[0].average[Nave].dP    = 0;
-
-    // XXX for now, set the average mag data to NULL
-    outcat[0].average[Nave].Nmeasure  	  = 0;
-    outcat[0].average[Nave].Nmissing  	  = 0;
-    outcat[0].average[Nave].Xp        	  = NAN_S_SHORT;
-    outcat[0].average[Nave].measureOffset = Nmeas;
-    outcat[0].average[Nave].missingOffset = -1;
-    outcat[0].average[Nave].flags         = 0;
 
     for (j = 0; j < Nsec; j++) {
-      outcat[0].secfilt[Nave*Nsec+j].M  = NAN;
-      outcat[0].secfilt[Nave*Nsec+j].dM = NAN;
-      outcat[0].secfilt[Nave*Nsec+j].Xm = NAN_S_SHORT;
+      dvo_secfilt_init (&outcat[0].secfilt[Nave*Nsec+j]);
     }
 
@@ -181,4 +164,5 @@
     for (j = 0; valid && (j < Nmodel); j++) {
       n = modelRow[j];
+      dvo_measure_init (&outcat[0].measure[Nmeas]);
       outcat[0].measure[Nmeas].dR        = 0.0;
       outcat[0].measure[Nmeas].dD        = 0.0;
Index: trunk/Ohana/src/addstar/src/addstar.c
===================================================================
--- trunk/Ohana/src/addstar/src/addstar.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/addstar.c	(revision 34405)
@@ -27,4 +27,9 @@
   options = args (argc, argv, options);
 
+  if (options.mode == ADDSTAR_MODE_CREATE_ID) {
+    addstar_create_ID ();
+    exit (0);
+  }
+
   sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   if (sky == NULL) {
Index: trunk/Ohana/src/addstar/src/addstar_create_ID.c
===================================================================
--- trunk/Ohana/src/addstar/src/addstar_create_ID.c	(revision 34405)
+++ trunk/Ohana/src/addstar/src/addstar_create_ID.c	(revision 34405)
@@ -0,0 +1,43 @@
+# include "addstar.h"
+
+// If this function is unable to open the image table, it creates a new one
+// set the database ID in the Image.dat header
+int addstar_create_ID () {
+
+  int status;
+  FITS_DB db;
+
+  /*** update the image table ***/
+  /* setup image table format and lock */
+  db.mode   = dvo_catalog_catmode (CATMODE);
+  db.format = dvo_catalog_catformat (CATFORMAT);
+  status    = dvo_image_lock (&db, ImageCat, 2.0, LCK_XCLD);  // shorter timeout?
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", db.filename);
+
+  /* load or create the image table */
+  if (db.dbstate == LCK_EMPTY) {
+    if (VERBOSE) fprintf (stderr, "can't find %s, creating a new one\n", ImageCat);
+    dvo_image_create (&db, GetZeroPoint());
+  } else {
+    if (!dvo_image_load (&db, VERBOSE, FORCE_READ)) {
+      Shutdown ("can't read image catalog %s", db.filename);
+    }
+    if (!dvo_image_createID (&db.header)) {
+      fprintf (stderr, "failed to add database ID\n");
+      exit (1);
+    }
+  }
+  fseeko (db.f, 0, SEEK_SET);
+
+  status = fwrite (db.header.buffer, 1, db.header.datasize, db.f);
+  if (status != db.header.datasize) {
+    fprintf (stderr, "failed to write data to image header\n");
+    exit (1);
+  }
+
+  dvo_image_unlock (&db);
+
+  return TRUE;
+}
+
+// NOTE: Photcodes (and ZERO_POINT) and ImageCat are set in ConfigInit.c
Index: trunk/Ohana/src/addstar/src/args.c
===================================================================
--- trunk/Ohana/src/addstar/src/args.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/args.c	(revision 34405)
@@ -32,4 +32,8 @@
   if ((N = get_argument (argc, argv, "-resort"))) {
     options.mode = ADDSTAR_MODE_RESORT;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-create-id"))) {
+    options.mode = ADDSTAR_MODE_CREATE_ID;
     remove_argument (N, &argc, argv);
   }
@@ -101,4 +105,5 @@
       if (options.mode == ADDSTAR_MODE_FAKEIMAGE) goto allow;
       if (options.mode == ADDSTAR_MODE_REFLIST) goto allow;
+      if (options.mode == ADDSTAR_MODE_CREATE_ID) goto allow;
       if (options.mode == ADDSTAR_MODE_REFCAT) {
 	  fprintf (stderr, "you have requested uploading from a catalog to the entire sky in one pass\n");
@@ -364,4 +369,5 @@
   }
 
+  if ((options.mode == ADDSTAR_MODE_CREATE_ID) && (argc == 1)) return (options);
   if ((options.mode == ADDSTAR_MODE_RESORT) && (argc == 1)) return (options);
   if (argc == 2) return (options);
@@ -378,4 +384,5 @@
   fprintf (stderr, "USAGE: addstar -fakeimage (ra) (dec) (theta) (name)\n");
   fprintf (stderr, "USAGE: addstar -resort (SkyRegion)\n");
+  fprintf (stderr, "USAGE: addstar -add-id\n");
   fprintf (stderr, "USAGE: addstar -ppm (filename)\n");
   exit (2);
Index: trunk/Ohana/src/addstar/src/load2mass_catalog.c
===================================================================
--- trunk/Ohana/src/addstar/src/load2mass_catalog.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/load2mass_catalog.c	(revision 34405)
@@ -34,5 +34,5 @@
     catalog[0].average[Nave].Nmeasure  	   = 0;
     catalog[0].average[Nave].Nmissing  	   = 0;
-    catalog[0].average[Nave].Xp        	   = NAN_S_SHORT;
+    catalog[0].average[Nave].ChiSqAve  	   = NAN_S_SHORT;
     catalog[0].average[Nave].measureOffset = Nmeas;
     catalog[0].average[Nave].missingOffset = -1;
Index: trunk/Ohana/src/addstar/src/mkcmf.c
===================================================================
--- trunk/Ohana/src/addstar/src/mkcmf.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/mkcmf.c	(revision 34405)
@@ -14,4 +14,5 @@
 void gauss_init (int Nbin);
 double rnd_gauss (double mean, double sigma);
+void writeStars_PS1_V4 (FTable *ftable, double *X, double *Y, double *M, unsigned int *Flag, int Nstars);
 void writeStars_PS1_V3 (FTable *ftable, double *X, double *Y, double *M, unsigned int *Flag, int Nstars);
 void writeStars_PS1_V2 (FTable *ftable, double *X, double *Y, double *M, unsigned int *Flag, int Nstars);
@@ -283,4 +284,8 @@
     found = TRUE;
   }
+  if (!strcmp(type, "PS1_V4")) {
+    writeStars_PS1_V4 (&ftable, X, Y, M, Flag, Nstars); 
+    found = TRUE;
+  }
   if (!found) {
     fprintf (stderr, "ERROR: unknown CMF type %s\n", type);
@@ -419,5 +424,5 @@
     stars[i].fy        = FY;
     stars[i].df        = DF;
-    stars[i].psfQual   = PSFQUAL;
+    stars[i].psfQF   = PSFQUAL;
     stars[i].nFrames   = 1;
   }
@@ -466,5 +471,5 @@
     stars[i].fy        = FY;
     stars[i].df        = DF;
-    stars[i].psfQual   = PSFQUAL;
+    stars[i].psfQF   = PSFQUAL;
     stars[i].nFrames   = 1;
     stars[i].flags     = FLAGS;
@@ -514,5 +519,5 @@
     stars[i].fy        = FY;
     stars[i].df        = DF;
-    stars[i].psfQual   = PSFQUAL;
+    stars[i].psfQF   = PSFQUAL;
     stars[i].nFrames   = 1;
     stars[i].flags     = FLAGS;
@@ -551,7 +556,7 @@
     // randomly give poor PSFQF values
     if ((BAD_PSFQF_FRAC > 0.0) && (drand48() < BAD_PSFQF_FRAC)) {
-      stars[i].psfQual   = 0.25;
+      stars[i].psfQF   = 0.25;
     } else {
-      stars[i].psfQual   = PSFQUAL;
+      stars[i].psfQF   = PSFQUAL;
     }
     
@@ -606,7 +611,7 @@
     // randomly give poor PSFQF values
     if ((BAD_PSFQF_FRAC > 0.0) && (drand48() < BAD_PSFQF_FRAC)) {
-      stars[i].psfQual   = 0.25;
+      stars[i].psfQF   = 0.25;
     } else {
-      stars[i].psfQual   = PSFQUAL;
+      stars[i].psfQF   = PSFQUAL;
     }
     
@@ -635,2 +640,62 @@
 }
 
+void writeStars_PS1_V4 (FTable *ftable, double *X, double *Y, double *M, unsigned int *Flag, int Nstars) {
+
+  int i;
+  CMF_PS1_V4 *stars;
+  float flux, fSN;
+
+  // XXX add gaussian-distributed noise based on counts
+  // this needs to make different output 'stars' entries depending on the desired type
+  ALLOCATE (stars, CMF_PS1_V4, Nstars);
+  gauss_init (2048);
+  for (i = 0; i < Nstars; i++) {
+    stars[i].detID = i;
+
+    flux = pow (10.0, -0.4*M[i]);
+    fSN = 1.0 / sqrt(flux);
+
+    stars[i].X = X[i];
+    stars[i].Y = Y[i];
+    stars[i].M = M[i];
+    stars[i].Map = M[i] - 0.05;
+
+    if (ADDNOISE) {
+      stars[i].X += FX * fSN * rnd_gauss(0.0, 1.0);
+      stars[i].Y += FY * fSN * rnd_gauss(0.0, 1.0);
+      stars[i].M += fSN*rnd_gauss(0.0, 1.0);
+    }
+
+    // randomly give poor PSFQF values
+    if ((BAD_PSFQF_FRAC > 0.0) && (drand48() < BAD_PSFQF_FRAC)) {
+      stars[i].psfQF     = 0.25;
+      stars[i].psfQFperf = 0.24;
+    } else {
+      stars[i].psfQF     = PSFQUAL;
+      stars[i].psfQFperf = MAX(PSFQUAL - 0.01, 0.0);
+    }
+    
+    stars[i].dX = FX * fSN;
+    stars[i].dY = FY * fSN;
+    stars[i].dM = fSN;
+
+    stars[i].Mpeak     = M[i] + 1.0;
+    stars[i].sky       = SKY;
+    stars[i].dSky      = DSKY;
+    stars[i].psfChisq  = PSFCHI;
+    stars[i].crNsigma  = CRN;
+    stars[i].extNsigma = EXTN;
+    stars[i].fx        = FX;
+    stars[i].fy        = FY;
+    stars[i].df        = DF;
+    stars[i].nFrames   = 1;
+    stars[i].flags     = Flag[i];
+
+    stars[i].kronFlux  = flux * 1.25;
+    stars[i].kronFluxErr = fSN * flux * 1.25;
+  }
+
+  gfits_table_set_CMF_PS1_V4 (ftable, stars, Nstars);
+  gfits_modify (ftable->header, "EXTTYPE",   "%s", 1, "PS1_V4");
+}
+
Index: trunk/Ohana/src/addstar/src/update_coords.c
===================================================================
--- trunk/Ohana/src/addstar/src/update_coords.c	(revision 34361)
+++ trunk/Ohana/src/addstar/src/update_coords.c	(revision 34405)
@@ -47,6 +47,6 @@
   dR2 = r2 / Npt - r*r;
   dD2 = d2 / Npt - d*d;
-  average[0].Xp = sqrt (dD2 + dR2 / SQ(cos(d*RAD_DEG)));
-  /* Xp is scatter in position in hundredths of arcsec */
+  average[0].ChiSqAve = sqrt (dD2 + dR2 / SQ(cos(d*RAD_DEG)));
+  /* ChiSqAve is supposed to be a chisq */
 
   return;
Index: trunk/Ohana/src/addstar/test/simple.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/simple.dvo	(revision 34361)
+++ trunk/Ohana/src/addstar/test/simple.dvo	(revision 34405)
@@ -4,4 +4,5 @@
 
 macro test.all
+  # test.fields (DVO schema) (CMF format)
   test.fields PS1_DEV_0 PS1_V1
   test.fields PS1_DEV_1 PS1_V1
@@ -9,4 +10,5 @@
   test.fields PS1_V2 	PS1_V1
   test.fields PS1_V3 	PS1_V1
+  test.fields PS1_V4 	PS1_V1
 
   test.fields PS1_DEV_0 PS1_V2
@@ -15,4 +17,5 @@
   test.fields PS1_V2 	PS1_V2
   test.fields PS1_V3 	PS1_V2
+  test.fields PS1_V4 	PS1_V4
 
   test.fields PS1_DEV_0 PS1_V3
@@ -21,4 +24,5 @@
   test.fields PS1_V2 	PS1_V3
   test.fields PS1_V3 	PS1_V3
+  test.fields PS1_V4 	PS1_V4
 
   test.fields PS1_DEV_0 PS1_V4
@@ -27,4 +31,5 @@
   test.fields PS1_V2 	PS1_V4
   test.fields PS1_V3 	PS1_V4
+  test.fields PS1_V4 	PS1_V4
 end  
 
@@ -36,5 +41,6 @@
   end
 
-  tapPLAN 51
+  echo ""
+  echo "testing --- CMF = $1, DVO = $2 ---"
 
   exec rm -rf catdir.test
@@ -45,7 +51,14 @@
   mkinput
   exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC -type $1
-  exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass
+  if ($TAP_VERBOSE)
+    exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass
+  else
+    exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass >& tmp.log
+  end
 
   list testfields -copy testfields_$1
+
+  # set the number of tests based on the testfields list
+  tapPLAN {3 + 3*($testfields:n - 1)}
 
   catdir catdir.test
@@ -77,6 +90,12 @@
   for i 1 $testfields:n
     list name -split $testfields:$i
-    if ("$name:0" == "SKIP") continue
-    if ("$name:2" == "SKIP") continue
+    if ("$name:0" == "SKIP") 
+      tapSKIP 3
+      continue
+    end
+    if ("$name:2" == "SKIP") 
+      tapSKIP 3
+      continue
+    end
     # must be the same length
     set v1 = $name:0
@@ -106,5 +125,5 @@
     # THETA is stored to only (360/65536) deg accuracy
     if ("$name:0" == "PSF_THETA")
-      echo $MEAN
+      # echo $MEAN
       tapOK {abs($MEAN)  < 0.006} "$name:0 vs $name:2 (MEAN)"
       tapOK {abs($SIGMA) < 0.001} "$name:0 vs $name:2 (SIGMA)"
@@ -304,2 +323,52 @@
   N_FRAMES          : SKIP # not ingested into DVO
 end
+
+# this list is good for PS1_V4
+list testfields_PS1_V4
+  IPP_IDET          : detid	
+  X_PSF             : xccd	
+  Y_PSF             : yccd	
+  X_PSF_SIG         : xccd:err # FAIL
+  Y_PSF_SIG         : yccd:err # FAIL
+  POSANGLE          : SKIP # astrometry is not calibrated in the cmf
+  PLTSCALE          : SKIP # astrometry is not calibrated in the cmf
+  PSF_INST_MAG      : mag:inst	
+  PSF_INST_MAG_SIG  : mag:err	
+  PSF_INST_FLUX     : SKIP # not ingested into DVO
+  PSF_INST_FLUX_SIG : SKIP # not ingested into DVO
+  AP_MAG_STANDARD   : mag:aperinst # FAIL
+  AP_MAG_RAW        : SKIP # not ingested into DVO
+  AP_MAG_RADIUS     : SKIP # not ingested into DVO
+  CAL_PSF_MAG       : SKIP # photometry is not calibrated in the cmf
+  CAL_PSF_MAG_SIG   : SKIP # photometry is not calibrated in the cmf
+  RA_PSF            : SKIP # astrometry is not calibrated in the cmf
+  DEC_PSF           : SKIP # astrometry is not calibrated in the cmf
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO
+  SKY               : sky	
+  SKY_SIG           : sky_err	
+  PSF_CHISQ         : psf_chisq	
+  CR_NSIGMA         : cr_nsigma	
+  EXT_NSIGMA        : ext_nsigma
+  PSF_MAJOR         : FWHM_MAJ	
+  PSF_MINOR         : FWHM_MIN	
+  PSF_THETA         : THETA # FAIL
+  PSF_QF            : PSF_QF	
+  PSF_QF_PERFECT    : SKIP # not ingested into DVO
+  PSF_NDOF          : PSF_NDOF
+  PSF_NPIX          : PSF_NPIX
+  MOMENTS_XX        : MXX
+  MOMENTS_XY        : MXY
+  MOMENTS_YY        : MYY
+  MOMENTS_M3C       : SKIP # not ingested into DVO
+  MOMENTS_M3S       : SKIP # not ingested into DVO
+  MOMENTS_M4C       : SKIP # not ingested into DVO
+  MOMENTS_M4S       : SKIP # not ingested into DVO
+  MOMENTS_R1        : SKIP # not ingested into DVO
+  MOMENTS_RH        : SKIP # not ingested into DVO
+  KRON_FLUX         : mag:kroninst
+  KRON_FLUX_ERR     : mag:kronerr
+  KRON_FLUX_INNER   : SKIP # not ingested into DVO
+  KRON_FLUX_OUTER   : SKIP # not ingested into DVO
+  FLAGS             : phot_flags
+  N_FRAMES          : SKIP # not ingested into DVO
+end
Index: trunk/Ohana/src/addstar/test/tap.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/tap.dvo	(revision 34361)
+++ trunk/Ohana/src/addstar/test/tap.dvo	(revision 34405)
@@ -2,4 +2,5 @@
 
 if (not($?TAP_BREAK)) set TAP_BREAK = 0
+if (not($?TAP_VERBOSE)) set TAP_VERBOSE = 0
 
 macro tapOK
@@ -10,5 +11,7 @@
 
   if ($1)
-    echo "ok : $2"
+    if ($TAP_VERBOSE)
+      echo "ok : $2"
+    end
     $TAP_LAST = 1
   else
@@ -42,6 +45,6 @@
   end
 
-  $TAP_NSKIP ++
-  $TAP_NDONE ++
+  $TAP_NSKIP += $1
+  $TAP_NDONE += $1
 end
 
