Index: /branches/czw_branch/20101203/Ohana/src/addstar/Makefile
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/Makefile	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/Makefile	(revision 30118)
@@ -72,4 +72,6 @@
 $(SRC)/replace_match.$(ARCH).o \
 $(SRC)/resort_catalog.$(ARCH).o \
+$(SRC)/resort_threaded.$(ARCH).o \
+$(SRC)/resort_unthreaded.$(ARCH).o \
 $(SRC)/StarOps.$(ARCH).o \
 $(SRC)/ReadStarsFITS.$(ARCH).o \
Index: /branches/czw_branch/20101203/Ohana/src/addstar/doc/resort_catalog.alloc.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/doc/resort_catalog.alloc.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/doc/resort_catalog.alloc.c	(revision 30118)
@@ -0,0 +1,158 @@
+# include "addstar.h"
+
+void resort_catalog_old (Catalog *catalog) {
+
+  off_t *next_meas;
+  off_t Naves, Nmeas;
+  double dtime;
+  struct timeval start, stop;
+
+  if (catalog[0].sorted == TRUE) return;
+
+  gettimeofday (&start, NULL);
+
+  /* internal counters */
+  Nmeas = catalog[0].Nmeasure;
+  Naves = catalog[0].Naverage;
+  
+  /* set up pointers for linked list of measure, missing */
+  next_meas = build_measure_links (catalog[0].average, Naves, catalog[0].measure, Nmeas);
+
+  catalog[0].sorted = TRUE;
+  catalog[0].measure = sort_measure (catalog[0].average, Naves, catalog[0].measure, Nmeas, next_meas);
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "  match time %9.4f sec for %7lld measures, %6lld average\n", dtime, (long long) Nmeas, (long long) Naves);
+
+  return;
+}
+
+# define myAbort(MSG) { fprintf (stderr, "%s\n", MSG); abort(); }
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+// 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)(MEAS[A] < MEAS[B])
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+# undef SWAPFUNC
+# undef COMPARE
+}
+
+# define MARKTIME(MSG,...) { \
+  float dtime; \
+  gettimeofday (&stop, (void *) NULL); \
+  dtime = DTIME (stop, start); start = stop; \
+  fprintf (stderr, MSG, __VA_ARGS__); }
+
+// XXX : where is the time going?  perhaps the ALLOCATE?
+// XXX : I don't thnk his is getting the right answer yet.
+
+static int NMEASURE = 0;
+static off_t *measureSeq = NULL;
+static off_t *averageSeq = NULL;
+static Measure *measureTMP = NULL;
+
+void resort_catalog (Catalog *catalog) {
+
+  off_t Naverage, Nmeasure;
+  Measure *measure;
+  Average *average;
+  off_t i, j, N, currentAve;
+
+  struct timeval start, stop;
+
+  if (catalog[0].sorted == TRUE) return;
+
+  gettimeofday (&start, NULL);
+
+  /* internal counters */
+  Nmeasure = catalog[0].Nmeasure;
+  Naverage = catalog[0].Naverage;
+
+  measure = catalog[0].measure;
+  average = catalog[0].average;
+  
+  // 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
+
+  if (!measureSeq) {
+    NMEASURE = MAX(Nmeasure, 1000);
+    ALLOCATE (measureSeq, off_t,   NMEASURE);
+    ALLOCATE (averageSeq, off_t,   NMEASURE);
+    ALLOCATE (measureTMP, Measure, NMEASURE);
+  }    
+
+  if (Nmeasure > NMEASURE) {
+    NMEASURE = Nmeasure;
+    REALLOCATE (measureSeq, off_t,   NMEASURE);
+    REALLOCATE (averageSeq, off_t,   NMEASURE);
+    REALLOCATE (measureTMP, Measure, NMEASURE);
+  }
+  
+  // MARKTIME("array allocation: %f sec\n", dtime);
+
+  for (i = 0; i < Nmeasure; i++) {
+    measureSeq[i] = i;
+    averageSeq[i] = measure[i].averef;
+    
+    myAssert(average[averageSeq[i]].objID == measure[measureSeq[i]].objID, "object / detection mismatch");
+    myAssert(average[averageSeq[i]].catID == measure[measureSeq[i]].catID, "object / detection mismatch");
+  }
+  
+  // MARKTIME("create index: %f sec\n", dtime);
+
+  SortAveMeasMatch(measureSeq, averageSeq, Nmeasure);
+  
+  // MARKTIME("sort : %f sec\n", dtime);
+
+  // copy the measurements in the sorted order
+  for (i = 0; i < Nmeasure; i++) {
+    j = measureSeq[i];
+    measureTMP[i] = measure[j];
+  }
+
+  // save the sorted list in the correct order
+  for (i = 0; i < Nmeasure; i++) {
+    measure[i] = measureTMP[i];
+  }
+
+  // MARKTIME("assign measure : %f sec\n", dtime);
+
+  // update the values of average.measureOffset and average.Nmeasure
+
+  N = 0;
+  currentAve = averageSeq[0];
+  average[currentAve].measureOffset = 0;
+  for (i = 0; i < Nmeasure; i++) {
+    if (averageSeq[i] != currentAve) {
+      average[currentAve].Nmeasure = N;
+      N = 0;
+      currentAve = averageSeq[i];
+      average[currentAve].measureOffset = i;
+    }
+    N++;
+  }
+  N++;
+  average[currentAve].Nmeasure = N;
+
+  // MARKTIME("update Nmeasure : %f sec\n", dtime);
+
+  MARKTIME("  match time %9.4f sec for %7lld measures, %6lld average\n", dtime, (long long) Nmeasure, (long long) Naverage);
+
+  // FREE (measureSeq);
+  // FREE (averageSeq);
+
+  return;
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/addstar/include/addstar.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/include/addstar.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/include/addstar.h	(revision 30118)
@@ -125,4 +125,6 @@
 float   ZPT_ERR_PHU;
 
+int     OLD_RESORT;
+
 // carries the mosaic into gstars
 
@@ -135,4 +137,5 @@
 double MIN_FWHM_X;
 double MIN_FWHM_Y;
+int    NTHREADS;
 
 /* modify server behavior (make this an addstar cleanup mode?) */
@@ -207,5 +210,8 @@
 Stars     *rd_gsc                 PROTO((char *filename, unsigned int *nstars));
 int        replace_match          PROTO((Average *average, Measure *measure, Stars *star));
+int        resort_threaded        PROTO((AddstarClientOptions *options, SkyTable *sky));
+int        resort_unthreaded      PROTO((AddstarClientOptions *options, SkyTable *sky));
 void       resort_catalog         PROTO((Catalog *catalog));
+void       resort_catalog_old     PROTO((Catalog *catalog));
 Stars     *ReadStarsFITS          PROTO((FILE *f, Header *header, Header *in_theader, unsigned int *nstars));
 Stars     *ReadStarsTEXT          PROTO((FILE *f, unsigned int *nstars));
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsFITS.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 30118)
@@ -22,5 +22,5 @@
 
   /* load the table data */
-  if (!gfits_fread_ftable_data (f, &table)) {
+  if (!gfits_fread_ftable_data (f, &table, FALSE)) {
     fprintf (stderr, "ERROR: can't read table header\n");
     exit (1);
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsSDSS.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsSDSS.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/ReadStarsSDSS.c	(revision 30118)
@@ -60,5 +60,5 @@
 
   /* load the table data */
-  if (!gfits_fread_ftable_data (f, &table)) {
+  if (!gfits_fread_ftable_data (f, &table, FALSE)) {
     fprintf (stderr, "ERROR: can't read table header\n");
     exit (1);
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/addstar.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/addstar.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/addstar.c	(revision 30118)
@@ -34,4 +34,13 @@
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
+  if (options.mode == M_RESORT) {
+    if (NTHREADS == 0) {
+      resort_unthreaded (&options, sky);
+    } else {
+      resort_threaded (&options, sky);
+    }
+    exit (0);
+  }
+
   stars = NULL;
 
@@ -157,5 +166,9 @@
 	}
 
-	resort_catalog (&catalog);
+	if (OLD_RESORT) { 
+	  resort_catalog_old (&catalog);
+	} else {
+	  resort_catalog (&catalog);
+	}
 	Nsubset = 1;
 	break;
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/args.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/args.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/args.c	(revision 30118)
@@ -34,4 +34,9 @@
     remove_argument (N, &argc, argv);
   }
+  OLD_RESORT = FALSE;
+  if ((N = get_argument (argc, argv, "-old-resort"))) {
+    remove_argument (N, &argc, argv);
+    OLD_RESORT = TRUE;
+  }
   if ((N = get_argument (argc, argv, "-fakeimage"))) {
     options.mode = M_FAKEIMAGE;
@@ -62,4 +67,12 @@
     remove_argument (N, &argc, argv);
     PMM_CCD_TABLE = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  // number of worker threads for resort (must have at least one worker thread)
+  NTHREADS = 0;
+  if ((N = get_argument (argc, argv, "-threads"))) {
+    remove_argument (N, &argc, argv);
+    NTHREADS = MAX(0, atoi (argv[N]));
     remove_argument (N, &argc, argv);
   }
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_catalog.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_catalog.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_catalog.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "addstar.h"
 
-void resort_catalog (Catalog *catalog) {
+void resort_catalog_old (Catalog *catalog) {
 
   off_t *next_meas;
@@ -28,2 +28,109 @@
   return;
 }
+
+# define myAbort(MSG) { fprintf (stderr, "%s\n", MSG); abort(); }
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+// 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)(MEAS[A] < MEAS[B])
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+# undef SWAPFUNC
+# undef COMPARE
+}
+
+# define MARKTIME(MSG,...) { \
+  float dtime; \
+  gettimeofday (&stop, (void *) NULL); \
+  dtime = DTIME (stop, start); start = stop; \
+  fprintf (stderr, MSG, __VA_ARGS__); }
+
+// XXX : where is the time going?  perhaps the ALLOCATE?
+// XXX : I don't thnk his is getting the right answer yet.
+
+void resort_catalog (Catalog *catalog) {
+
+  off_t Naverage, Nmeasure;
+  Measure *measure;
+  Average *average;
+  off_t i, j, N, currentAve;
+
+  off_t *measureSeq = NULL;
+  off_t *averageSeq = NULL;
+  Measure *measureTMP = NULL;
+
+  if (catalog[0].sorted == TRUE) return;
+
+  // struct timeval start, stop;
+  // gettimeofday (&start, NULL);
+
+  /* internal counters */
+  Nmeasure = catalog[0].Nmeasure;
+  Naverage = catalog[0].Naverage;
+
+  measure = catalog[0].measure;
+  average = catalog[0].average;
+  
+  // 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
+
+  ALLOCATE (measureSeq, off_t,   Nmeasure);
+  ALLOCATE (averageSeq, off_t,   Nmeasure);
+
+  for (i = 0; i < Nmeasure; i++) {
+    measureSeq[i] = i;
+    averageSeq[i] = measure[i].averef;
+    
+    myAssert(average[averageSeq[i]].objID == measure[measureSeq[i]].objID, "object / detection mismatch");
+    myAssert(average[averageSeq[i]].catID == measure[measureSeq[i]].catID, "object / detection mismatch");
+  }
+  
+  SortAveMeasMatch(measureSeq, averageSeq, Nmeasure);
+  // MARKTIME("sort : %f sec\n", dtime);
+
+  // copy the measurements in the sorted order
+  ALLOCATE (measureTMP, Measure, Nmeasure);
+  for (i = 0; i < Nmeasure; i++) {
+    j = measureSeq[i];
+    measureTMP[i] = measure[j];
+  }
+  // MARKTIME("assign measure : %f sec\n", dtime);
+
+  // update the values of average.measureOffset and average.Nmeasure
+  FREE(measure);
+  catalog[0].measure = measureTMP;
+
+  N = 0;
+  currentAve = averageSeq[0];
+  average[currentAve].measureOffset = 0;
+  for (i = 0; i < Nmeasure; i++) {
+    if (averageSeq[i] != currentAve) {
+      average[currentAve].Nmeasure = N;
+      N = 0;
+      currentAve = averageSeq[i];
+      average[currentAve].measureOffset = i;
+    }
+    N++;
+  }
+  N++;
+  average[currentAve].Nmeasure = N;
+  // MARKTIME("update Nmeasure : %f sec\n", dtime);
+
+  // MARKTIME("  match time %9.4f sec for %7lld measures, %6lld average\n", dtime, (long long) Nmeasure, (long long) Naverage);
+
+  FREE (measureSeq);
+  FREE (averageSeq);
+
+  return;
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_threaded.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_threaded.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_threaded.c	(revision 30118)
@@ -0,0 +1,238 @@
+# include "addstar.h"
+# include <pthread.h>
+
+enum {
+  TS_WAIT,
+  TS_RUN,
+  TS_DONE,
+  TS_FAIL,
+  TS_EXIT,
+};
+
+typedef struct {
+  int iThread;
+  int state;
+  int nosort;
+  char *filename;
+  SkyRegion *region;
+  off_t Naverage;
+  off_t Nmeasure;
+} ThreadData;
+
+// the thread manager has three states: 
+// WAIT : no data is available for this thread
+// RUN  : data is available, attempt to process
+// DONE : completed the analysis, wait for harvest
+// FAIL : serious error resulting in system shutdown
+
+void *resort_thread_job (void *inputData) {
+
+  Catalog catalog;
+  ThreadData *threadData = (ThreadData *) inputData;
+
+  while (TRUE) {
+
+    while (threadData->state != TS_RUN) {
+      usleep (100);
+    }
+
+    // set the parameters which guide catalog open/load/create
+    catalog.filename  = threadData->filename;
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS;
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+  
+    // an error exit status here is a significant error (disk I/O or file access)
+    if (!dvo_catalog_open (&catalog, threadData->region, VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      threadData->Naverage = 0;
+      threadData->Nmeasure = 0;
+      threadData->state = TS_FAIL;
+      continue;
+    }
+
+    // Naves_disk == 0 implies an empty catalog file, skip empty catalogs
+    if (catalog.Naves_disk == 0) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      threadData->Naverage = 0;
+      threadData->Nmeasure = 0;
+      threadData->state = TS_DONE;
+      continue;
+    }
+
+    // this is an overloaded value to mean 'force sort'
+    if (threadData->nosort == 3) catalog.sorted = FALSE;
+
+    if (OLD_RESORT) { 
+      resort_catalog_old (&catalog);
+    } else {
+      resort_catalog (&catalog);
+    }
+
+    /* report total updated values */
+    threadData->Naverage = catalog.Naverage;
+    threadData->Nmeasure = catalog.Nmeasure;
+    // fprintf (stderr, "done in thread %d, %d aves, %d meas\n", threadData->iThread, (int) threadData->Naverage, (int) threadData->Nmeasure);
+
+    // write out catalog, if appropriate
+    SetProtect (TRUE);
+    dvo_catalog_save (&catalog, VERBOSE);
+    SetProtect (FALSE);
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+    threadData->state = TS_DONE;
+  }
+  return NULL;
+}
+
+int resort_threaded (AddstarClientOptions *options, SkyTable *sky) {
+
+  int j, launched, done, Nwait, Nrun;
+
+  off_t i;
+  off_t Naverage, Nmeasure;
+
+  ThreadData *threadData;
+  pthread_t *threads;
+
+  double dtime;
+  struct timeval start, stop;
+  gettimeofday (&start, NULL);
+
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+  
+  // in these cases, limit the sky catalogs to an existing subset
+  if (options->existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to "OFF_T_FMT" regions\n",  skylist[0].Nregions);
+
+  if (options->only_images) {
+    fprintf (stderr, "-image (only images) makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->only_match) {
+    fprintf (stderr, "-only-match makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->nosort == 1) {
+    fprintf (stderr, "-nosort makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->update) {
+    fprintf (stderr, "-update makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->calibrate) {
+    fprintf (stderr, "-cal (calibrate) makes no sense with -resort\n");
+    exit (2);
+  }
+
+  ALLOCATE(threads, pthread_t, NTHREADS);
+  ALLOCATE(threadData, ThreadData, NTHREADS);
+  for (i = 0; i < NTHREADS; i++) {
+    threadData[i].state = TS_WAIT;
+    threadData[i].iThread = i;
+  }
+  for (i = 0; i < NTHREADS; i++) {
+    pthread_create (&threads[i], NULL, &resort_thread_job, (void *) &threadData[i]);
+  }
+
+  // if we catch a failure at any point, goto the failure block and wait for threads to finish
+  // continue in this loop until all regions have been launched (though not finished)
+  Naverage = Nmeasure = 0;
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    launched = FALSE;
+    while (!launched) {
+
+      // are any threads done? can we harvest them?
+      for (j = 0; j < NTHREADS; j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_DONE) continue;
+	Naverage += threadData[j].Naverage;
+	Nmeasure += threadData[j].Nmeasure;
+	// fprintf (stderr, "harvested thread %d, %d aves, %d meas (sums: %d aves, %d meas)\n", threadData[j].iThread, (int) threadData[j].Naverage, (int) threadData[j].Nmeasure, (int) Naverage, (int) Nmeasure);
+	threadData[j].state = TS_WAIT;
+      }
+	
+      // are any threads available? can we launch this job?
+      for (j = 0; !launched && (j < NTHREADS); j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_WAIT) continue;
+	threadData[j].nosort = options->nosort;
+	threadData[j].filename = skylist[0].filename[i];
+	threadData[j].region = skylist[0].regions[i];
+	threadData[j].state = TS_RUN;
+	launched = TRUE;
+      }
+      if (!launched) usleep (100);
+    }
+  }
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+    // are any threads done? can we harvest them?
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_DONE) continue;
+      Naverage += threadData[j].Naverage;
+      Nmeasure += threadData[j].Nmeasure;
+      threadData[j].state = TS_WAIT;
+    }
+
+    // how many are waiting now?
+    Nwait = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_WAIT) continue;
+      Nwait ++;
+    }
+
+    if (Nwait < NTHREADS) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for, "OFF_T_FMT" average, "OFF_T_FMT" measure\n", dtime, Naverage, Nmeasure);
+
+  // for (i = 0; i < NTHREADS; i++) {
+  //   pthread_cancel(threads[i]);
+  // }
+  // free (threads);
+  free (threadData);
+
+  return TRUE;
+
+failure:
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+
+    // how many are still running?
+    Nrun = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state != TS_RUN) continue;
+      Nrun ++;
+    }
+
+    if (Nrun) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+  exit (1);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_unthreaded.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_unthreaded.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/src/resort_unthreaded.c	(revision 30118)
@@ -0,0 +1,105 @@
+# include "addstar.h"
+
+int resort_unthreaded (AddstarClientOptions *options, SkyTable *sky) {
+
+  off_t i;
+  off_t Naverage, Nmeasure;
+  Catalog catalog;
+
+  double dtime;
+  struct timeval start, stop;
+
+  gettimeofday (&start, NULL);
+
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+  
+  // in these cases, limit the sky catalogs to an existing subset
+  if (options->existing_regions) {
+    SkyList *tmp;
+    tmp = SkyListExistingSubset (skylist, CATDIR);
+    SkyListFree (skylist);
+    skylist = tmp;
+  }
+  if (VERBOSE) fprintf (stderr, "writing to "OFF_T_FMT" regions\n",  skylist[0].Nregions);
+
+  if (options->only_images) {
+    fprintf (stderr, "-image (only images) makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->only_match) {
+    fprintf (stderr, "-only-match makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->nosort == 1) {
+    fprintf (stderr, "-nosort makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->update) {
+    fprintf (stderr, "-update makes no sense with -resort\n");
+    exit (2);
+  }
+  if (options->calibrate) {
+    fprintf (stderr, "-cal (calibrate) makes no sense with -resort\n");
+    exit (2);
+  }
+
+  // XXX ALLOCATE catalog[Nthreads]
+
+  /* match stars to existing catalog data (or otherwise manipulate catalog data) */
+  Naverage = Nmeasure = 0;
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    // XXX BLOCK here for an empty thread
+
+    // set the parameters which guide catalog open/load/create
+    catalog.filename  = skylist[0].filename[i];
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+    catalog.catflags  = LOAD_AVES | LOAD_MEAS;
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+
+    // an error exit status here is a significant error (disk I/O or file access)
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+      exit (2);
+    }
+
+    // Naves_disk == 0 implies an empty catalog file, skip empty catalogs
+    if (catalog.Naves_disk == 0) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    // this is an overloaded value to mean 'force sort'
+    if (options->nosort == 3) catalog.sorted = FALSE;
+
+    // XXX send these to a free thread
+
+    if (OLD_RESORT) { 
+      resort_catalog_old (&catalog);
+    } else {
+      resort_catalog (&catalog);
+    }
+
+    // XXX wait for completed threads
+
+    /* report total updated values */
+    Naverage += catalog.Naverage;
+    Nmeasure += catalog.Nmeasure;
+
+    // write out catalog, if appropriate
+    SetProtect (TRUE);
+    dvo_catalog_save (&catalog, VERBOSE);
+    SetProtect (FALSE);
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for, "OFF_T_FMT" average, "OFF_T_FMT" measure\n", dtime, Naverage, Nmeasure);
+
+  return TRUE;
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/addstar/test/dvomerge.dvo
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/addstar/test/dvomerge.dvo	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/addstar/test/dvomerge.dvo	(revision 30118)
@@ -4,5 +4,5 @@
 
 # create 2 populated catdirs, each with a couple of cmf files
-macro test.dvomerge.update
+macro test.dvomerge.continue
 
   tapPLAN 51
@@ -16,4 +16,123 @@
 
   mkinput
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec 10.0 20.0
+  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec 10.0 20.0
+  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec 9.9 20.0
+  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec 9.9 20.0
+  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 05:00:00 -radec 10.0 19.9
+  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 06:00:00 -radec 10.0 19.9
+  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 07:00:00 -radec 9.9 19.9
+  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+
+  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 08:00:00 -radec 9.9 19.9
+  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+
+  break
+
+  exec rsync -auc catdir.test2/ catdir.test3/
+
+  date -var t1 -seconds -reftime 1276000000
+  exec dvomerge catdir.test1 into catdir.test3
+  date -var t2 -seconds -reftime 1276000000
+  echo "merge time: {$t2 - $t1}"
+
+  catdir catdir.test3
+  skyregion {$RA-1} {$RA+1} {$DEC-1} {$DEC+1} 
+  mextract ra dec mag
+  create n 0 ra[]
+  subset r0 = ra if (n % 4 == 0)
+  subset r1 = ra if (n % 4 == 1)
+  subset r2 = ra if (n % 4 == 2)
+  subset r3 = ra if (n % 4 == 3)
+
+  catdir catdir.test1/
+  mextract RA DEC MAG
+  create N 0 RA[]
+  subset R0 = RA if (N % 2 == 0)
+  subset R1 = RA if (N % 2 == 1)
+
+  set dr0 = r0 - R0
+  vstat -q dr0
+  tapOK {abs($MEAN)  < 0.001} "ra (in - 0) vs ra (out - 0) (MEAN)"
+  tapOK {abs($SIGMA) < 0.001} "ra (in - 0) vs ra (out - 0) (SIGMA)"
+
+  set dr1 = r1 - R1
+  vstat -q dr1
+  tapOK {abs($MEAN)  < 0.001} "ra (in - 0) vs ra (out - 0) (MEAN)"
+  tapOK {abs($SIGMA) < 0.001} "ra (in - 0) vs ra (out - 0) (SIGMA)"
+
+  catdir catdir.test2/
+  mextract RA DEC MAG
+  create N 0 RA[]
+  subset R2 = RA if (N % 2 == 0)
+  subset R3 = RA if (N % 2 == 1)
+
+  set dr2 = r2 - R2
+  vstat -q dr2
+  tapOK {abs($MEAN)  < 0.001} "ra (in - 0) vs ra (out - 0) (MEAN)"
+  tapOK {abs($SIGMA) < 0.001} "ra (in - 0) vs ra (out - 0) (SIGMA)"
+
+  set dr3 = r3 - R3
+  vstat -q dr3
+  tapOK {abs($MEAN)  < 0.001} "ra (in - 0) vs ra (out - 0) (MEAN)"
+  tapOK {abs($SIGMA) < 0.001} "ra (in - 0) vs ra (out - 0) (SIGMA)"
+
+  # check on updates to imageID
+  catdir catdir.test3
+  imextract imageID
+  sort imageID
+  tapOK {imageID[]  == 4} "image IDs exist"
+  tapOK {imageID[0] == 1} "updated image IDs"
+  tapOK {imageID[1] == 2} "updated image IDs"
+  tapOK {imageID[2] == 3} "updated image IDs"
+  tapOK {imageID[3] == 4} "updated image IDs"
+
+  catdir catdir.test3
+  mextract imageID, time
+  set id = imageID
+  set t = time
+  imextract imageID, time
+
+  for i 0 time[]
+    subset T = t if (id == imageID[$i])
+    set dT = T - time[$i]
+    vstat dT 
+    tapOK {abs($MEAN)  < 0.00001} "time for measure ID $i (MEAN)"
+    tapOK {abs($SIGMA) < 0.00001} "time for measure ID $i (SIGMA)"
+  end
+
+  # exec rm test.in.txt test.cmf
+  # exec rm -rf catdir.test1
+  # exec rm -rf catdir.test2
+  # exec rm -rf catdir.test3
+
+  tapDONE
+end
+
+# create 2 populated catdirs, each with a couple of cmf files
+macro test.dvomerge.update
+
+  tapPLAN 51
+
+  exec rm -rf catdir.test1
+  exec rm -rf catdir.test2
+  exec rm -rf catdir.test3
+
+  $RA = 10.0
+  $DEC = 20.0
+
+  mkinput
   exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
   exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
@@ -27,4 +146,6 @@
   exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
   exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+
+  break
 
   exec rsync -auc catdir.test2/ catdir.test3/
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/Makefile
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/Makefile	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/Makefile	(revision 30118)
@@ -22,8 +22,13 @@
 all: dvomerge dvoconvert dvosecfilt
 
+#  $(SRC)/dvomergeContinue.$(ARCH).o
+
 DVOMERGE = \
 $(SRC)/dvomerge.$(ARCH).o \
 $(SRC)/dvomergeUpdate.$(ARCH).o \
 $(SRC)/dvomergeCreate.$(ARCH).o \
+$(SRC)/dvomergeUpdate_threaded.$(ARCH).o \
+$(SRC)/dvomergeFromList.$(ARCH).o \
+$(SRC)/dvomergeImageIDs.$(ARCH).o \
 $(SRC)/dvo_image_merge_dbs.$(ARCH).o \
 $(SRC)/SetSignals.$(ARCH).o \
@@ -70,5 +75,29 @@
 $(BIN)/dvosecfilt.$(ARCH) : $(DVOSECFILT)
 
-INSTALL = dvomerge dvoconvert dvosecfilt
+DVOREPAIR = \
+$(SRC)/dvorepair.$(ARCH).o \
+$(SRC)/dvorepairFixCPT.$(ARCH).o \
+$(SRC)/dvorepairImagesVsMeasures.$(ARCH).o \
+$(SRC)/dvorepairDeleteImageList.$(ARCH).o \
+$(SRC)/dvorepairFixImages.$(ARCH).o \
+$(SRC)/psps_ids.$(ARCH).o \
+$(SRC)/LoadImages.$(ARCH).o \
+$(SRC)/ReadDeleteList.$(ARCH).o \
+$(SRC)/match_image.$(ARCH).o \
+$(SRC)/help.$(ARCH).o \
+$(SRC)/ImageOps.$(ARCH).o
+
+$(DVOREPAIR)  : $(INC)/dvomerge.h
+
+$(BIN)/dvorepair.$(ARCH) : $(DVOREPAIR)
+
+DVOVERIFY = \
+$(SRC)/dvoverify.$(ARCH).o
+
+$(DVOVERIFY)  : $(INC)/dvomerge.h
+
+$(BIN)/dvoverify.$(ARCH) : $(DVOVERIFY)
+
+INSTALL = dvomerge dvoconvert dvosecfilt dvorepair dvoverify
 
 # dependancy rules for binary code #########################
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/doc/notes.txt
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/doc/notes.txt	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/doc/notes.txt	(revision 30118)
@@ -0,0 +1,24 @@
+
+2010.11.08 : DVO repairs
+
+  * I have made a dvorepair program that reconstructs cpt files from a valid cpm file
+
+  * the ThreePi.V1 database got busted; I think we have the following issues:
+
+    * cpt files which are short (and can be fixed with the command above)
+
+    * Image.dat has many image that have no matching detections (repeated dvomerge runs after the failure)
+
+    * a number of cpm files which are short : in this case, I believe
+      these files have all detections before the failure, but are
+      missing some of the detections from the failure. 
+
+  * repair step 1 : scan image IDs on the database : count the number
+    of detections for each image ID and find those image IDs which are
+    missing detections
+
+  * remove images that are missing their detections
+
+  * create repaired cpm files excluding the now-orphaned detections
+
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/include/dvomerge.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/include/dvomerge.h	(revision 30118)
@@ -17,4 +17,7 @@
 # include <glob.h>
 
+# define myAbort(MSG) { fprintf (stderr, "%s\n", MSG); abort(); }
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
 int    VERBOSE;
 char   CATDIR[256];
@@ -25,4 +28,5 @@
 float  RADIUS;
 int    SKY_DEPTH;
+int    NTHREADS;
 char   *ALTERNATE_PHOTCODE_FILE;
 
@@ -65,5 +69,5 @@
 SkyList   *SkyTablePopulatedList_old  PROTO((SkyTable *sky, off_t Ns, off_t Ne));
 
-int        LoadCatalog            PROTO((Catalog *catalog, SkyRegion *region, char *filename, char *mode));
+int        LoadCatalog            PROTO((Catalog *catalog, SkyRegion *region, char *filename, char *mode, int Nsecfilt));
 
 int        merge_catalogs_new     PROTO((SkyRegion *region, Catalog *output, Catalog *input, int *secflitMap));
@@ -86,2 +90,25 @@
 off_t 	   dvo_map_image_ID       PROTO((IDmapType *IDmap, off_t oldID));
 int   	   dvo_update_image_IDs   PROTO((IDmapType *IDmap, Catalog *catalog));
+
+// dvorepair prototypes
+Image     *LoadImages         	  PROTO((FITS_DB *db, char *filename, off_t *Nimage));
+Image     *MatchImage         	  PROTO((Image *image, off_t Nimage, unsigned int time, short int source, unsigned int imageID));
+off_t      match_image        	  PROTO((Image *image, off_t Nimage, unsigned int T, short int S));
+
+int        SaveImages             PROTO((FITS_DB *oldDB, char *filename, Image *imagesOut, off_t Nout));
+
+int 	   dvorepairFixCPT        PROTO((int argc, char **argv));
+int 	   dvorepairImagesVsMeasures PROTO((int argc, char **argv));
+int 	   dvorepairDeleteImageList PROTO((int argc, char **argv));
+int 	   dvorepairFixImages     PROTO((int argc, char **argv));
+
+int       *ReadDeleteList         PROTO((char *filename, int *nindex));
+int 	   RepairTableCPT         PROTO((char *cptFilenameSrc, char *cptFilenameTgt, char *cpsFilenameSrc, char *cpsFilenameTgt, Measure *measure, off_t Nmeasure, Image *image, off_t Nimage, char catformat));
+void       dvorepair_help         PROTO((int argc, char **argv));
+
+off_t      getTgtIndex            PROTO((e_time start, e_time stop, short photcode, off_t *TgtIndex, e_time *TgtTimes, short *TgtCodes, off_t NimagesTgt));
+void       SortTgtByTimes         PROTO((e_time *S, off_t *I, short *C, off_t N));
+int 	   dvo_image_match_dbs    PROTO((IDmapType *IDmap, FITS_DB *tgt, FITS_DB *src));
+int 	   dvomergeImagesGetMap   PROTO((IDmapType *IDmap, char *input, char *output));
+int        dvomergeFromList       PROTO((int argc, char **argv));
+int 	   dvomergeUpdate_threaded PROTO((int argc, char **argv));
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ImageOps.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ImageOps.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ImageOps.c	(revision 30118)
@@ -0,0 +1,22 @@
+# include "dvomerge.h"
+
+Image *MatchImage (Image *image, off_t Nimage, unsigned int time, short int source, unsigned int imageID) { 
+
+  int m = -1;
+
+  if ((imageID != 0) && (imageID < Nimage)) {
+    // imageID is in range for the array of images. If the table is still in order and
+    // no images have been deleted the index of the image we are looking for will be imageID - 1
+    // If this is the case, we have it. Otherwise we'll have to go search for it below
+    int guess = (int) imageID - 1;
+    if (image[guess].imageID == imageID) {
+        m = guess;
+    }
+  } 
+  if (m == -1) {
+    m = match_image (image, Nimage, time, source);
+  }
+  if (m == -1) return (NULL);
+  if (!FindMosaicForImage (image, Nimage, m)) return (NULL);
+  return (&image[m]);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadCatalog.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadCatalog.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadCatalog.c	(revision 30118)
@@ -1,9 +1,9 @@
 # include "dvomerge.h"
 
-int LoadCatalog (Catalog *catalog, SkyRegion *region, char *filename, char *mode) {
+int LoadCatalog (Catalog *catalog, SkyRegion *region, char *filename, char *mode, int Nsecfilt) {
 
     // set the parameters which guide catalog open/load/create
     catalog[0].filename  = filename;
-    catalog[0].Nsecfilt  = GetPhotcodeNsecfilt ();
+    catalog[0].Nsecfilt  = Nsecfilt;
 
     // always load all of the data (if any exists)
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadImages.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadImages.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/LoadImages.c	(revision 30118)
@@ -0,0 +1,46 @@
+# include "dvomerge.h"
+
+Image *LoadImages (FITS_DB *db, char *filename, off_t *Nimage) {
+
+  int status;
+  Image *image;
+  double ZeroPoint;
+  
+  myAssert(filename, "programming errror");
+  myAssert(Nimage, "programming errror");
+    
+  gfits_db_init (db);
+  db->lockstate = LCK_SOFT;
+  db->timeout   = 120.0;
+
+  if (!gfits_db_lock (db, filename)) {
+    fprintf (stderr, "error opening image catalog %s (1)\n", filename);
+    return (NULL);
+  }
+
+  if (db->dbstate == LCK_EMPTY) {
+    fprintf (stderr, "note: image catalog is empty\n");
+    ALLOCATE (image, Image, 1);
+    *Nimage = 1;
+    return (image);
+  }
+
+  status = dvo_image_load (db, TRUE, FALSE);
+  gfits_db_close (db);
+
+  if (!status) {
+    fprintf (stderr, "problem loading image database table\n");
+    return (NULL);
+  }
+
+  image = gfits_table_get_Image (&db->ftable, Nimage, &db->swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    return (NULL);
+  }
+
+  gfits_scan (&db->header, "ZERO_PT", "%lf", 1, &ZeroPoint);
+  SetZeroPoint (ZeroPoint);
+
+  return (image);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ReadDeleteList.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ReadDeleteList.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/ReadDeleteList.c	(revision 30118)
@@ -0,0 +1,100 @@
+# include "dvomerge.h"
+
+int *ReadDeleteList(char *filename, int *nindex) {
+
+  int j, index, Nindex, NINDEX, *indexList, Nline;
+  int Nstart, Nbytes, Nread, status;
+  char *c0, *c1, *space, *buffer;
+
+  char *indexPoint = NULL;
+  FILE *f = fopen (filename, "r");
+  myAssert(f, "failed to open delete list");
+  
+  Nindex = 0;
+  NINDEX = 1000;
+  ALLOCATE(indexList, int, NINDEX);
+
+  ALLOCATE (buffer, char, 0x10001);
+  bzero (buffer, 0x10001);
+
+  Nstart = 0;
+  Nline = 0;
+  while (1) {
+    Nbytes = 0x10000 - Nstart;
+    bzero (&buffer[Nstart], Nbytes);
+    Nread = fread (&buffer[Nstart], 1, Nbytes, f);
+    if (ferror (f)) {
+      perror ("error reading data file");
+      exit (1);
+    }
+    if (Nread == 0) break; // end of data
+    // nbytes = Nread + Nstart;
+    
+    status = TRUE;
+    c0 = buffer; 
+    while (status) {
+      // identify the range of the line
+      c1 = strchr (c0, '\n');
+      if (c1 == (char *) NULL) {
+	Nstart = strlen (c0);
+	memmove (buffer, c0, Nstart);
+	break;
+      } else {
+	*c1 = 0;
+      }      
+      if (*c0 == '#') goto next_line;
+
+      // confirm 'image' as first token:
+      if (strncmp(c0, "image", 5)) {
+	fprintf (stderr, "error on line %d: missing 'image' token\n", Nline);
+	goto next_line;
+      }
+
+      // confirm we have 7 fields broken by 6 spaces:
+      space = c0;
+      for (j = 0; j < 6; j++) {
+	space = strchr(space, ' '); 
+	if (!space) {
+	  fprintf (stderr, "line only has %d word(s)\n", j + 1);
+	  goto next_line;
+	}
+	space ++;
+	if (j == 1) {
+	  indexPoint = space + 1;
+	}
+      }
+
+      // save the value we have found:
+      index = atoi(indexPoint);
+      indexList[Nindex] = index;
+
+      // fprintf (stderr, "index: %d, line: %s\n", index, c0);
+
+      Nindex ++;
+      if (Nindex == NINDEX) {
+	NINDEX += 1000;
+	REALLOCATE (indexList, int, NINDEX);
+      }
+      
+    next_line:
+      Nline ++;
+      c0 = c1 + 1;
+    }
+  }
+
+  *nindex = Nindex;
+  return (indexList);
+}
+
+/* Delete List Format:
+   image o5252g0035o.140669.cm.51017.smf[XY11.hdr] (219974) : 368 vs 375
+   image o5252g0051o.140685.cm.51123.smf[XY11.hdr] (226417) : 350 vs 356
+   image o5399g0207o.194950.cm.98351.smf[XY46.hdr] (1683277) : 10341 vs 10347
+   image o5464g0284o.230438.cm.123774.smf[XY21.hdr] (2634913) : 214 vs 242
+   image o5464g0305o.230459.cm.123795.smf[XY21.hdr] (2635758) : 232 vs 257
+   image o5465g0306o.231171.cm.124201.smf[XY01.hdr] (2654941) : 0 vs 494
+   image o5465g0306o.231171.cm.124201.smf[XY02.hdr] (2654942) : 10 vs 813
+   image o5465g0306o.231171.cm.124201.smf[XY10.hdr] (2654947) : 0 vs 534
+   image o5465g0306o.231171.cm.124201.smf[XY11.hdr] (2654948) : 0 vs 447
+*/
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/args.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/args.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/args.c	(revision 30118)
@@ -15,4 +15,11 @@
     remove_argument (N, argc, argv);
     ALTERNATE_PHOTCODE_FILE = strdup(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  NTHREADS = 0;
+  if ((N = get_argument (*argc, argv, "-threads"))) {
+    remove_argument (N, argc, argv);
+    NTHREADS = MAX(0, atoi(argv[N]));
     remove_argument (N, argc, argv);
   }
@@ -36,5 +43,5 @@
   }
 
-  if ((*argc != 6) && (*argc != 4)) dvomerge_usage();
+  if ((*argc < 4) || (*argc > 6)) dvomerge_usage();
   return TRUE;
 }
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 30118)
@@ -2,4 +2,108 @@
 
 void sort_IDmap (IDmapType *IDmap);
+
+off_t getTgtIndex (e_time start, e_time stop, short photcode, off_t *TgtIndex, e_time *TgtTimes, short *TgtCodes, off_t NimagesTgt) {
+
+  // use bisection to find the starting entry by time
+
+  off_t Nlo, Nhi, N;
+
+  // find the last TGT before start
+  Nlo = 0; Nhi = NimagesTgt;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (TgtTimes[N] < start) {
+      Nlo = MAX(N, 0);
+    } else {
+      Nhi = MIN(N + 1, NimagesTgt);
+    }
+  }
+
+  // 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 < NimagesTgt; N++) { 
+    if (TgtTimes[N] < start) continue;
+    if (TgtTimes[N] > stop) return (-1);
+    if (TgtCodes[N] != photcode) continue;
+    return (TgtIndex[N]);
+  }
+  return (-1);
+}
+
+// sort two times vectors and an index by first time vector
+void SortTgtByTimes (e_time *S, off_t *I, short *C, off_t N) {
+
+# define SWAPFUNC(A,B){ e_time tmp_t; off_t tmp_i; short tmp_c; 	\
+  tmp_t = S[A]; S[A] = S[B]; S[B] = tmp_t; \
+  tmp_i = I[A]; I[A] = I[B]; I[B] = tmp_i; \
+  tmp_c = C[A]; C[A] = C[B]; C[B] = tmp_c; \
+}
+# define COMPARE(A,B)(S[A] < S[B])
+
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+
+}
+
+// we have two tables; 'tgt' contains some exposures from 'src' : find them and match a map
+int dvo_image_match_dbs (IDmapType *IDmap, FITS_DB *tgt, FITS_DB *src) {
+
+  Image *imagesSrc, *imagesTgt;
+  off_t NimagesSrc, NimagesTgt;
+  off_t iSrc, iTgt;
+  off_t  *TgtIndex;
+  e_time *TgtTimes;
+  short  *TgtCodes;
+ 
+  imagesSrc = gfits_table_get_Image (&src[0].ftable, &NimagesSrc, &src[0].swapped);
+  if (!imagesSrc) {
+    fprintf (stderr, "ERROR: failed to read images from src\n");
+    exit (2);
+  }
+
+  imagesTgt = gfits_table_get_Image (&tgt[0].ftable, &NimagesTgt, &tgt[0].swapped);
+  if (!imagesTgt) {
+    fprintf (stderr, "ERROR: failed to read images from tgt\n");
+    exit (2);
+  }
+
+  ALLOCATE (IDmap->old, off_t, NimagesSrc);
+  ALLOCATE (IDmap->new, off_t, NimagesSrc);
+  IDmap->Nmap = NimagesSrc;
+
+  // match by time and photcode
+  ALLOCATE (TgtIndex, off_t,  NimagesTgt);
+  ALLOCATE (TgtTimes, e_time, NimagesTgt);
+  ALLOCATE (TgtCodes, short,  NimagesTgt);
+
+  // save the Index, Times, Codes for all TGT images
+  for (iTgt = 0; iTgt < NimagesTgt; iTgt++) {
+    TgtIndex[iTgt] = iTgt;
+    TgtTimes[iTgt] = imagesTgt[iTgt].tzero;
+    TgtCodes[iTgt] = imagesTgt[iTgt].photcode;
+  }
+
+  // sort the index, start, and stop by the start times:
+  SortTgtByTimes (TgtTimes, TgtIndex, TgtCodes, NimagesTgt);
+
+  for (iSrc = 0; iSrc < NimagesSrc; iSrc++) {
+    iTgt = getTgtIndex (imagesSrc[iSrc].tzero, imagesSrc[iSrc].tzero + (int) imagesSrc[iSrc].exptime, imagesSrc[iSrc].photcode, TgtIndex, TgtTimes, TgtCodes, NimagesTgt);
+    if (iTgt < 0) Shutdown ("failure to match images: %s\n", imagesSrc[iSrc].name);
+    IDmap[0].old[iSrc] = imagesSrc[iSrc].imageID;
+    IDmap[0].new[iSrc] = imagesTgt[iTgt].imageID;
+  }
+
+  FREE(TgtIndex);
+  FREE(TgtTimes);
+  FREE(TgtCodes);
+
+  // sort IDmap->old,new on the basis of IDmap->old:
+  sort_IDmap (IDmap);
+
+  return TRUE;
+}
 
 // merge db2 into db1
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoconvert.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoconvert.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoconvert.c	(revision 30118)
@@ -6,5 +6,5 @@
   char filename[256], *input, *output;
 
-  int depth;
+  int depth, Nsecfilt;
   off_t i, j, Ns, Ne;
   SkyTable *outsky, *insky;
@@ -32,4 +32,6 @@
       exit (1);
     }
+    Nsecfilt = GetPhotcodeNsecfilt();
+
     // save the photcodes in the output catdir
     sprintf (filename, "%s/Photcodes.dat", output);
@@ -67,5 +69,5 @@
 
     // load / create output catalog
-    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w");
+    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w", Nsecfilt);
 
     // combine only tables at equal or larger depth
@@ -77,5 +79,5 @@
 
       // load input catalog
-      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");
+      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r", Nsecfilt);
 
       // skip empty input catalogs
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomerge.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomerge.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomerge.c	(revision 30118)
@@ -8,8 +8,18 @@
   dvomerge_args (&argc, argv);
 
-  // XXX require both inputs to be sorted?
-
-  if (argc == 6) dvomergeCreate (argc, argv);
-  if (argc == 4) dvomergeUpdate (argc, argv);
+  if (argc == 6) {
+    if (!strcasecmp (argv[2], "and")) {
+      dvomergeCreate (argc, argv);
+    } else {
+      dvomergeFromList (argc, argv);
+    }
+  }
+  if ((argc == 4) || (argc == 5)) {
+    if (NTHREADS) {
+      dvomergeUpdate_threaded (argc, argv);
+    } else {
+      dvomergeUpdate (argc, argv);
+    }
+  }
   dvomerge_usage();
   exit (2); // cannot reach here.
@@ -18,6 +28,7 @@
 /* we have two possible modes of operation:
 
-   Create : dvomerge (in1) and (in2) to (out) -- create a new db from two input dbs
-   Update : dvomerge (in) into (out)          -- merge a new db into an existing db
+   Create   : dvomerge (in1) and (in2) to (out) -- create a new db from two input dbs
+   Update   : dvomerge (in) into (out)          -- merge a new db into an existing db
+   Continue : dvomerge (in) into (out) continue -- merge a new db into an existing db
 
 */
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue.c	(revision 30118)
@@ -0,0 +1,164 @@
+# include "dvomerge.h"
+
+int dvomergeContinue (int argc, char **argv) {
+
+  int depth;
+  off_t i, j, Ns, Ne;
+  SkyTable *outsky, *insky;
+  SkyList *outlist, *inlist;
+  Catalog incatalog, outcatalog;
+  char filename[256], *input, *output;
+  IDmapType IDmap;
+  PhotCodeData *inputPhotcodes;
+  PhotCodeData *outputPhotcodes;
+  int *secfiltMap = NULL;
+  int NsecfiltInput, NsecfiltOutput;
+
+  double dtime;
+  struct timeval start, stop;
+  gettimeofday (&start, NULL);
+
+  if (strcasecmp (argv[2], "into")) dvomerge_usage();
+  if (strcasecmp (argv[4], "continue")) dvomerge_usage();
+
+  input  = argv[1];
+  output = argv[3];
+
+  if (ALTERNATE_PHOTCODE_FILE) {
+    fprintf (stderr, "cannot specify photcodes when merging into an existing catdir\n");
+    exit (1);
+  }
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", input);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading input database directory %s\n", input);
+    exit (1);
+  }	
+  inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
+
+  // since we are merging the input db into the output db, the output defines the photcode
+  // table & db layout but, this requires the output to exist.  if it does not, instead use the
+  // input.
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", output);
+  if (LoadPhotcodes (filename, NULL, FALSE)) {
+
+    outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
+
+    secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
+    if (!secfiltMap) {
+      fprintf (stderr, "failed to map input secfilt photcodes to output photcodes table\n");
+      exit (1);
+    }
+  } else {
+    fprintf(stderr, "%s not found using photcodes from %s/Photcodes.dat\n", filename, input);
+    outputPhotcodes = inputPhotcodes;
+    NsecfiltOutput = NsecfiltInput;
+
+    if (!check_dir_access (output, VERBOSE)) {
+      fprintf (stderr, "error creating output database directory %s\n", output);
+      exit (1);
+    }
+    SetPhotcodeTable(inputPhotcodes);
+    if (!SavePhotcodesFITS (filename)) {
+      fprintf (stderr, "error saving photcode table in %s/Photcodes.dat\n", output);
+      exit (1);
+    }
+  }
+
+  // need to determine the mapping from the input to the output images
+  dvomergeImagesGetMap (&IDmap, input, output);
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  if (!insky) {
+      Shutdown ("can't read SkyTable for %s", input);
+  }
+  SkyTableSetFilenames (insky, input, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // generate an output table populated at the desired depth
+  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  if (!outsky) {
+      Shutdown ("can't read or create SkyTable for %s", output);
+  }
+  SkyTableSetFilenames (outsky, output, "cpt");
+
+  // loop over the populatable output tables; check for data in input in the corresponding regions
+
+  SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  depth = inlist[0].regions[Ns][0].depth;
+  
+  SetPhotcodeTable(NULL);
+
+  // loop over the populated input regions
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+    if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
+
+    // load / create output catalog (if catalog does not exist, it will be created)
+    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r", NsecfiltInput);
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+	dvo_catalog_unlock (&incatalog);
+	dvo_catalog_free (&incatalog);
+	continue;
+    }
+
+    // combine only tables at equal or larger depth
+      
+    // load in all of the tables from input for this region
+    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
+    // compare to a slightly reduced footprint
+    float dPos = 2.0/3600.0;
+    outlist = SkyListByBounds (outsky, depth, inlist[0].regions[i][0].Rmin + dPos, inlist[0].regions[i][0].Rmax - dPos, inlist[0].regions[i][0].Dmin + dPos, inlist[0].regions[i][0].Dmax - dPos);
+    for (j = 0; j < outlist[0].Nregions; j++) {
+      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
+
+      // load input catalog
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w", NsecfiltOutput);
+
+      dvo_update_image_IDs (&IDmap, &incatalog);
+      merge_catalogs_old (&outsky[0].regions[j], &outcatalog, &incatalog, RADIUS, secfiltMap);
+
+      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+      // if we receive a signal which would cause us to exit, wait until the full catalog is written
+      SetProtect (TRUE);
+      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
+	exit (1);
+      }
+      SetProtect (FALSE);
+
+      dvo_catalog_unlock (&outcatalog);
+      dvo_catalog_free (&outcatalog);
+
+      fprintf (stderr, "merged %s into %s\n", inlist[0].regions[i][0].name, outlist[0].regions[j][0].name);
+    }
+    SkyListFree (outlist);
+
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+  }
+
+  // save the output sky table copy
+  sprintf (filename, "%s/SkyTable.fits", output);
+  check_file_access (filename, TRUE, TRUE, VERBOSE);
+  if (!SkyTableSave (outsky, filename)) {
+    fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
+    exit (1);
+  }
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec\n", dtime);
+
+  exit (0);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue_threaded.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue_threaded.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeContinue_threaded.c	(revision 30118)
@@ -0,0 +1,313 @@
+# include "dvomerge.h"
+# include <pthread.h>
+
+enum {
+  TS_WAIT,
+  TS_RUN,
+  TS_DONE,
+  TS_FAIL,
+  TS_EXIT,
+};
+
+typedef struct {
+  int iThread;
+  int state;
+  // elements used to carry data to the threadjob
+  char *name;
+  char *filename;
+  SkyRegion *region;
+  int NsecfiltInput;
+  int NsecfiltOutput;
+  IDmapType *IDmap;
+  SkyTable *outsky;
+  int *secfiltMap;
+  int depth;
+} ThreadData;
+
+void *dvomergeUpdate_threadjob (void *inputData) {
+
+  off_t j;
+  Catalog incatalog, outcatalog;
+  SkyList *outlist;
+
+  ThreadData *threadData = (ThreadData *) inputData;
+
+  while (TRUE) {
+
+    while (threadData->state != TS_RUN) {
+      usleep (100);
+    }
+
+    if (VERBOSE) fprintf (stderr, "input: %s\n", threadData->name);
+
+    // load / create output catalog (if catalog does not exist, it will be created)
+    LoadCatalog (&incatalog, threadData->region, threadData->filename, "r", threadData->NsecfiltInput);
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+      dvo_catalog_unlock (&incatalog);
+      dvo_catalog_free (&incatalog);
+      threadData->state = TS_DONE;
+      continue;
+    }
+
+    // combine only tables at equal or larger depth.
+
+    // NOTE: this requirement is especially important for the threaded version: if the
+    // output catalog is guaranteed to be the same size or finer than the input, then two
+    // input catalogs cannot collide on their target output catalog.
+      
+    // load in all of the tables from input for this region
+    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
+    // compare to a slightly reduced footprint
+    float dPos = 2.0/3600.0;
+    outlist = SkyListByBounds (threadData->outsky, threadData->depth, threadData->region->Rmin + dPos, threadData->region->Rmax - dPos, threadData->region->Dmin + dPos, threadData->region->Dmax - dPos);
+    for (j = 0; (j < outlist[0].Nregions) && (threadData->state != TS_FAIL); j++) {
+      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
+
+      // load input catalog
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w", threadData->NsecfiltOutput);
+
+      dvo_update_image_IDs (threadData->IDmap, &incatalog);
+      merge_catalogs_old (&threadData->outsky->regions[j], &outcatalog, &incatalog, RADIUS, threadData->secfiltMap);
+
+      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+      // if we receive a signal which would cause us to exit, wait until the full catalog is written
+      SetProtect (TRUE);
+      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
+	threadData->state = TS_FAIL;
+	continue;
+      }
+      SetProtect (FALSE);
+
+      dvo_catalog_unlock (&outcatalog);
+      dvo_catalog_free (&outcatalog);
+
+      fprintf (stderr, "merged %s into %s\n", threadData->name, outlist[0].regions[j][0].name);
+    }
+    SkyListFree (outlist);
+
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+    threadData->state = TS_DONE;
+  }
+  return NULL;
+}
+
+int dvomergeUpdate_threaded (int argc, char **argv) {
+
+  int j, launched, done, Nwait, Nrun;
+
+  ThreadData *threadData;
+  pthread_t *threads;
+
+  int depth;
+  off_t i, Ns, Ne;
+  SkyTable *outsky, *insky;
+  SkyList *inlist;
+  char filename[256], *input, *output;
+  IDmapType IDmap;
+  PhotCodeData *inputPhotcodes;
+  PhotCodeData *outputPhotcodes;
+  int *secfiltMap = NULL;
+  int NsecfiltInput, NsecfiltOutput;
+
+  double dtime;
+  struct timeval start, stop;
+  gettimeofday (&start, NULL);
+
+  CONTINUE = FALSE;
+  if (strcasecmp (argv[2], "into")) dvomerge_usage();
+  if (argc == 5) {
+    if (strcasecmp (argv[4], "continue")) dvomerge_usage();
+    CONTINUE = TRUE;
+  }
+
+  input  = argv[1];
+  output = argv[3];
+
+  if (ALTERNATE_PHOTCODE_FILE) {
+    fprintf (stderr, "cannot specify photcodes when merging into an existing catdir\n");
+    exit (1);
+  }
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", input);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading input database directory %s\n", input);
+    exit (1);
+  }	
+  inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
+
+  // since we are merging the input db into the output db, the output defines the photcode
+  // table & db layout but, this requires the output to exist.  if it does not, instead use the
+  // input.
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", output);
+  if (LoadPhotcodes (filename, NULL, FALSE)) {
+
+    outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
+
+    secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
+    if (!secfiltMap) {
+      fprintf (stderr, "failed to map input secfilt photcodes to output photcodes table\n");
+      exit (1);
+    }
+  } else {
+    fprintf(stderr, "%s not found using photcodes from %s/Photcodes.dat\n", filename, input);
+    outputPhotcodes = inputPhotcodes;
+    NsecfiltOutput = NsecfiltInput;
+
+    if (!check_dir_access (output, VERBOSE)) {
+      fprintf (stderr, "error creating output database directory %s\n", output);
+      exit (1);
+    }
+    SetPhotcodeTable(inputPhotcodes);
+    if (!SavePhotcodesFITS (filename)) {
+      fprintf (stderr, "error saving photcode table in %s/Photcodes.dat\n", output);
+      exit (1);
+    }
+  }
+
+  if (CONTINUE) {
+    // need to determine the mapping from the input to the output images
+    dvomergeImagesGetMap (&IDmap, input, output);
+  } else {
+    dvomergeImagesUpdate (&IDmap, input, output);
+  }
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  if (!insky) {
+      Shutdown ("can't read SkyTable for %s", input);
+  }
+  SkyTableSetFilenames (insky, input, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // generate an output table populated at the desired depth
+  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  if (!outsky) {
+      Shutdown ("can't read or create SkyTable for %s", output);
+  }
+  SkyTableSetFilenames (outsky, output, "cpt");
+
+  // loop over the populatable output tables; check for data in input in the corresponding regions
+
+  SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  depth = inlist[0].regions[Ns][0].depth;
+  
+  SetPhotcodeTable(NULL);
+
+  ALLOCATE(threads, pthread_t, NTHREADS);
+  ALLOCATE(threadData, ThreadData, NTHREADS);
+  for (i = 0; i < NTHREADS; i++) {
+    threadData[i].state = TS_WAIT;
+    threadData[i].iThread = i;
+  }
+  for (i = 0; i < NTHREADS; i++) {
+    pthread_create (&threads[i], NULL, &dvomergeUpdate_threadjob, (void *) &threadData[i]);
+  }
+
+  // loop over the populated input regions
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    launched = FALSE;
+    while (!launched) {
+
+      // are any threads done? can we harvest them?
+      for (j = 0; j < NTHREADS; j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_DONE) continue;
+	// fprintf (stderr, "harvested thread %d\n", threadData[j].iThread);
+	threadData[j].state = TS_WAIT;
+      }
+	
+      // are any threads available? can we launch this job?
+      for (j = 0; !launched && (j < NTHREADS); j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_WAIT) continue;
+
+	threadData[j].name = inlist[0].regions[i][0].name;
+	threadData[j].filename = inlist[0].filename[i];
+	threadData[j].region = inlist[0].regions[i];
+	threadData[j].NsecfiltInput = NsecfiltInput;
+	threadData[j].NsecfiltOutput = NsecfiltOutput;
+	threadData[j].IDmap = &IDmap;
+	threadData[j].outsky = outsky;
+	threadData[j].secfiltMap = secfiltMap;
+	threadData[j].depth = depth;
+	threadData[j].state = TS_RUN;
+	launched = TRUE;
+      }
+      if (!launched) usleep (100);
+    }
+  }
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+    // are any threads done? can we harvest them?
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_DONE) continue;
+      threadData[j].state = TS_WAIT;
+    }
+
+    // how many are waiting now?
+    Nwait = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_WAIT) continue;
+      Nwait ++;
+    }
+
+    if (Nwait < NTHREADS) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+
+  // save the output sky table copy
+  sprintf (filename, "%s/SkyTable.fits", output);
+  check_file_access (filename, TRUE, TRUE, VERBOSE);
+  if (!SkyTableSave (outsky, filename)) {
+    fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
+    exit (1);
+  }
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec\n", dtime);
+
+  exit (0);
+
+failure:
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+
+    // how many are still running?
+    Nrun = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state != TS_RUN) continue;
+      Nrun ++;
+    }
+
+    if (Nrun) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+  exit (1);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeCreate.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeCreate.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeCreate.c	(revision 30118)
@@ -15,4 +15,5 @@
   char *input1, *input2, *output;
   IDmapType IDmap1, IDmap2;
+  int NsecfiltInput1, NsecfiltInput2, NsecfiltOutput;
 
   if (strcasecmp (argv[2], "and")) dvomerge_usage();
@@ -39,4 +40,5 @@
   }
   input1Photcodes = GetPhotcodeTable();
+  NsecfiltInput1 = GetPhotcodeNsecfilt();
 
   // Read the input2 photcodes
@@ -48,4 +50,5 @@
   }
   input2Photcodes = GetPhotcodeTable();
+  NsecfiltInput2 = GetPhotcodeNsecfilt();
 
   if (ALTERNATE_PHOTCODE_FILE) {
@@ -60,4 +63,5 @@
     }
     outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
 
     secfiltMap1 = GetSecFiltMap(outputPhotcodes, input1Photcodes);
@@ -74,4 +78,5 @@
     outputPhotcodes = input1Photcodes;
     codesFilename = filename1;
+    NsecfiltOutput = NsecfiltInput1;
     // secfitMap1 can remain NULL since input1 defines the set of codes
   }
@@ -84,6 +89,9 @@
   }
 
+  // trigger any dependencies, if any
+  SetPhotcodeTable(NULL);
+
   // save the output photcodes in the output catdir
-  SetPhotcodeTable(outputPhotcodes);
+  // SetPhotcodeTable(outputPhotcodes);
   sprintf (filename, "%s/Photcodes.dat", output);
   if (!check_file_access (filename, TRUE, TRUE, VERBOSE)) {
@@ -121,13 +129,13 @@
     if (VERBOSE) fprintf (stderr, "output: %s\n", outsky[0].regions[i].name);
 
-    if (outputPhotcodes) {
-        SetPhotcodeTable(outputPhotcodes);
-    }
+    // if (outputPhotcodes) {
+    //     SetPhotcodeTable(outputPhotcodes);
+    // }
     // load / create output catalog
-    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w");
-
-    if (input1Photcodes) {
-        SetPhotcodeTable(input1Photcodes);
-    }
+    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w", NsecfiltOutput);
+
+    // if (input1Photcodes) {
+    // SetPhotcodeTable(input1Photcodes);
+    // }
     // combine only tables at equal or larger depth
       
@@ -138,5 +146,5 @@
 
       // load input catalog (1)
-      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");
+      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r", NsecfiltInput1);
 
       // skip empty input catalogs
@@ -153,7 +161,7 @@
     SkyListFree (inlist);
 
-    if (input2Photcodes) {
-      SetPhotcodeTable(input2Photcodes);
-    }
+    // if (input2Photcodes) {
+    //   SetPhotcodeTable(input2Photcodes);
+    // }
 
     // load in all of the tables from input2 for this region
@@ -163,5 +171,5 @@
 
       // load input catalog (2)
-      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");
+      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r", NsecfiltInput2);
 
       // skip empty input catalogs
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeFromList.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeFromList.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeFromList.c	(revision 30118)
@@ -0,0 +1,158 @@
+# include "dvomerge.h"
+
+int dvomergeFromList (int argc, char **argv) {
+
+  off_t i, j;
+  Catalog incatalog, outcatalog;
+  char filename[256], *input, *output;
+  IDmapType IDmap;
+  PhotCodeData *inputPhotcodes;
+  PhotCodeData *outputPhotcodes;
+  int *secfiltMap = NULL;
+  char *listname, **list, inputfile[256], outputfile[256];
+  int Nlist, NLIST;
+  int NsecfiltInput, NsecfiltOutput;
+
+  if (strcasecmp (argv[2], "into")) dvomerge_usage();
+  if (strcasecmp (argv[4], "from")) dvomerge_usage();
+
+  input  = argv[1];
+  output = argv[3];
+  listname = argv[5];
+
+  Nlist = 0;
+  NLIST = 100;
+  ALLOCATE(list, char *, NLIST);
+  for (i = 0; i < NLIST; i++) {
+    ALLOCATE(list[i], char, 256);
+    memset(list[i], 0, 256);
+  }
+  
+  FILE *listfile = fopen(listname, "r");
+  myAssert(listfile, "error opening list");
+
+  for (i = 0; fscanf (listfile, "%s", list[i]) != EOF; i++) {
+    if (i == NLIST - 1) {
+      NLIST += 100;
+      REALLOCATE(list, char *, NLIST);
+      for (j = i + 1; j < NLIST; j++) {
+	ALLOCATE(list[j], char, 256);
+	memset(list[j], 0, 256);
+      }
+    }
+  }      
+  Nlist = i;
+  fclose(listfile);
+
+  if (ALTERNATE_PHOTCODE_FILE) {
+    fprintf (stderr, "cannot specify photcodes when merging into an existing catdir\n");
+    exit (1);
+  }
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", input);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading input database directory %s\n", input);
+    exit (1);
+  }	
+  inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
+
+  // since we are merging the input db into the output db, the output defines the photcode
+  // table & db layout but, this requires the output to exist.  if it does not, instead use the
+  // input.
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", output);
+  if (LoadPhotcodes (filename, NULL, FALSE)) {
+
+    outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
+
+    secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
+    if (!secfiltMap) {
+      fprintf (stderr, "failed to map input secfilt photcodes to output photcodes table\n");
+      exit (1);
+    }
+  } else {
+    fprintf(stderr, "%s not found using photcodes from %s/Photcodes.dat\n", filename, input);
+    outputPhotcodes = inputPhotcodes;
+    NsecfiltOutput = NsecfiltInput;
+
+    if (!check_dir_access (output, VERBOSE)) {
+      fprintf (stderr, "error creating output database directory %s\n", output);
+      exit (1);
+    }
+    SetPhotcodeTable(inputPhotcodes);
+    if (!SavePhotcodesFITS (filename)) {
+      fprintf (stderr, "error saving photcode table in %s/Photcodes.dat\n", output);
+      exit (1);
+    }
+  }
+
+  // XXX need to determine the mapping from the input to the output images
+  dvomergeImagesGetMap (&IDmap, input, output);
+
+  SetPhotcodeTable(NULL);
+
+  // loop over the populated input regions
+  for (i = 0; i < Nlist; i++) {
+    if (VERBOSE) fprintf (stderr, "input: %s\n", list[i]);
+
+    sprintf (inputfile,  "%s/%s", input,  list[i]);
+    sprintf (outputfile, "%s/%s", output, list[i]);
+
+    LoadCatalog (&incatalog, NULL, inputfile, "r", NsecfiltInput);
+
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+	dvo_catalog_unlock (&incatalog);
+	dvo_catalog_free (&incatalog);
+	continue;
+    }
+
+    // combine only tables at equal depth
+      
+    SkyRegion skyregion;
+    gfits_scan (&incatalog.header, "RA0",  "%f", 1, &skyregion.Rmin);
+    gfits_scan (&incatalog.header, "RA1",  "%f", 1, &skyregion.Rmax);
+    gfits_scan (&incatalog.header, "DEC0", "%f", 1, &skyregion.Dmin);
+    gfits_scan (&incatalog.header, "DEC1", "%f", 1, &skyregion.Dmax);
+
+    // load input catalog
+    // SetPhotcodeTable(outputPhotcodes);
+    LoadCatalog (&outcatalog, NULL, outputfile, "w", NsecfiltOutput);
+
+    if (outcatalog.Naverage == 0) {
+      gfits_modify (&outcatalog.header, "RA0",  "%f", 1, skyregion.Rmin);
+      gfits_modify (&outcatalog.header, "DEC0", "%f", 1, skyregion.Dmin);
+      gfits_modify (&outcatalog.header, "RA1",  "%f", 1, skyregion.Rmax);
+      gfits_modify (&outcatalog.header, "DEC1", "%f", 1, skyregion.Dmax);
+      gfits_modify (&outcatalog.header, "CATID", "%d", 1, incatalog.catID);
+      outcatalog.catID = incatalog.catID;
+    }
+
+    dvo_update_image_IDs (&IDmap, &incatalog);
+    merge_catalogs_old (&skyregion, &outcatalog, &incatalog, RADIUS, secfiltMap);
+    
+    outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+    // if we receive a signal which would cause us to exit, wait until the full catalog is written
+    SetProtect (TRUE);
+    if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+      fprintf (stderr, "ERROR: failed to save catalog %s\n", outputfile);
+      exit (1);
+    }
+    SetProtect (FALSE);
+    
+    fprintf (stderr, "merged %s into %s\n", inputfile, outputfile);
+
+    dvo_catalog_unlock (&outcatalog);
+    dvo_catalog_free (&outcatalog);
+    
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+  }
+
+  exit (0);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeImageIDs.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 30118)
@@ -0,0 +1,100 @@
+# include "dvomerge.h"
+
+/*** update the image table ***/
+int dvomergeImagesUpdate (IDmapType *IDmap, char *input, char *output) { 
+
+  FITS_DB inDB;
+  FITS_DB outDB;
+  int    status;
+
+  /*** load input1/Images.dat ***/
+  sprintf (ImageCat, "%s/Images.dat", input);
+  inDB.mode   = dvo_catalog_catmode (CATMODE);
+  inDB.format = dvo_catalog_catformat (CATFORMAT);
+  status       = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", inDB.filename);
+
+  // load the image table 
+  if (inDB.dbstate == LCK_EMPTY) {
+    IDmap->Nmap = 0;
+    return TRUE;
+  }
+  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
+    Shutdown ("can't read input image catalog %s", inDB.filename);
+  }
+
+  /*** load output/Images.dat ***/
+  sprintf (ImageCat, "%s/Images.dat", output);
+  outDB.mode   = dvo_catalog_catmode (CATMODE);
+  outDB.format = dvo_catalog_catformat (CATFORMAT);
+  status       = dvo_image_lock (&outDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", outDB.filename);
+
+  /* load the image table */
+  if (outDB.dbstate == LCK_EMPTY) {
+    dvo_image_create (&outDB, GetZeroPoint());
+  } else {
+    if (!dvo_image_load (&outDB, VERBOSE, TRUE)) {
+      Shutdown ("can't read output image catalog %s", outDB.filename);
+    }
+  }
+
+  // convert database table to internal structure & add to output image db
+  dvo_image_merge_dbs(IDmap, &outDB, &inDB);
+  dvo_image_unlock (&inDB); // unlock input
+
+  SetProtect (TRUE);
+  dvo_image_save (&outDB, VERBOSE);
+  SetProtect (FALSE);
+  dvo_image_unlock (&outDB); // unlock output
+
+  return TRUE;
+}
+
+/*** update the image table ***/
+int dvomergeImagesGetMap (IDmapType *IDmap, char *input, char *output) { 
+
+  FITS_DB inDB;
+  FITS_DB outDB;
+  int    status;
+
+  /*** load input1/Images.dat ***/
+  sprintf (ImageCat, "%s/Images.dat", input);
+  inDB.mode   = dvo_catalog_catmode (CATMODE);
+  inDB.format = dvo_catalog_catformat (CATFORMAT);
+  status       = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", inDB.filename);
+
+  // load the image table
+  if (inDB.dbstate == LCK_EMPTY) {
+    IDmap->Nmap = 0;
+    return TRUE;
+  }
+
+  // the input database is allowed to have no images 
+  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
+    Shutdown ("can't read input image catalog %s", inDB.filename);
+  }
+
+  /*** load output/Images.dat ***/
+  sprintf (ImageCat, "%s/Images.dat", output);
+  outDB.mode   = dvo_catalog_catmode (CATMODE);
+  outDB.format = dvo_catalog_catformat (CATFORMAT);
+  status       = dvo_image_lock (&outDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
+  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", outDB.filename);
+
+  /* load the image table */
+  if (outDB.dbstate == LCK_EMPTY) {
+    Shutdown ("only use -continue for an existing, partially merged database");
+  } 
+  if (!dvo_image_load (&outDB, VERBOSE, TRUE)) {
+    Shutdown ("can't read output image catalog %s", outDB.filename);
+  }
+
+  // convert database table to internal structure & add to output image db
+  dvo_image_match_dbs(IDmap, &outDB, &inDB);
+  dvo_image_unlock (&inDB); // unlock input
+  dvo_image_unlock (&outDB); // unlock output
+
+  return TRUE;
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 30118)
@@ -3,5 +3,5 @@
 int dvomergeUpdate (int argc, char **argv) {
 
-  int depth;
+  int depth, CONTINUE;
   off_t i, j, Ns, Ne;
   SkyTable *outsky, *insky;
@@ -13,6 +13,16 @@
   PhotCodeData *outputPhotcodes;
   int *secfiltMap = NULL;
+  int NsecfiltInput, NsecfiltOutput;
 
+  double dtime;
+  struct timeval start, stop;
+  gettimeofday (&start, NULL);
+
+  CONTINUE = FALSE;
   if (strcasecmp (argv[2], "into")) dvomerge_usage();
+  if (argc == 5) {
+    if (strcasecmp (argv[4], "continue")) dvomerge_usage();
+    CONTINUE = TRUE;
+  }
 
   input  = argv[1];
@@ -31,4 +41,5 @@
   }	
   inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
 
   // since we are merging the input db into the output db, the output defines the photcode
@@ -41,4 +52,5 @@
 
     outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
 
     secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
@@ -50,4 +62,6 @@
     fprintf(stderr, "%s not found using photcodes from %s/Photcodes.dat\n", filename, input);
     outputPhotcodes = inputPhotcodes;
+    NsecfiltOutput = NsecfiltInput;
+
     if (!check_dir_access (output, VERBOSE)) {
       fprintf (stderr, "error creating output database directory %s\n", output);
@@ -61,5 +75,10 @@
   }
 
-  dvomergeImagesUpdate (&IDmap, input, output);
+  if (CONTINUE) {
+    // need to determine the mapping from the input to the output images
+    dvomergeImagesGetMap (&IDmap, input, output);
+  } else {
+    dvomergeImagesUpdate (&IDmap, input, output);
+  }
 
   // load the sky table for the existing database
@@ -85,4 +104,6 @@
   depth = inlist[0].regions[Ns][0].depth;
   
+  SetPhotcodeTable(NULL);
+
   // loop over the populated input regions
   for (i = 0; i < inlist[0].Nregions; i++) {
@@ -90,7 +111,6 @@
     if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
 
-    SetPhotcodeTable(inputPhotcodes);
     // load / create output catalog (if catalog does not exist, it will be created)
-    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r");
+    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r", NsecfiltInput);
     // skip empty input catalogs
     if (!incatalog.Naves_disk) {
@@ -111,6 +131,5 @@
 
       // load input catalog
-      SetPhotcodeTable(outputPhotcodes);
-      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w");
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w", NsecfiltOutput);
 
       dvo_update_image_IDs (&IDmap, &incatalog);
@@ -121,5 +140,8 @@
       // if we receive a signal which would cause us to exit, wait until the full catalog is written
       SetProtect (TRUE);
-      dvo_catalog_save (&outcatalog, VERBOSE);
+      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
+	exit (1);
+      }
       SetProtect (FALSE);
 
@@ -143,56 +165,8 @@
   }
 
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec\n", dtime);
+
   exit (0);
 }
-
-/*** update the image table ***/
-int dvomergeImagesUpdate (IDmapType *IDmap, char *input, char *output) { 
-
-  FITS_DB inDB;
-  FITS_DB outDB;
-  int    status;
-
-  /*** load input1/Images.dat ***/
-  sprintf (ImageCat, "%s/Images.dat", input);
-  inDB.mode   = dvo_catalog_catmode (CATMODE);
-  inDB.format = dvo_catalog_catformat (CATFORMAT);
-  status       = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
-  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", inDB.filename);
-
-  // load the image table 
-  if (inDB.dbstate == LCK_EMPTY) {
-    // Shutdown ("can't find input image catalog %s", inDB.filename);
-    IDmap->Nmap = 0;
-    return TRUE;
-  }
-  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
-    Shutdown ("can't read input image catalog %s", inDB.filename);
-  }
-
-  /*** load output/Images.dat ***/
-  sprintf (ImageCat, "%s/Images.dat", output);
-  outDB.mode   = dvo_catalog_catmode (CATMODE);
-  outDB.format = dvo_catalog_catformat (CATFORMAT);
-  status       = dvo_image_lock (&outDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
-  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", outDB.filename);
-
-  /* load the image table */
-  if (outDB.dbstate == LCK_EMPTY) {
-    dvo_image_create (&outDB, GetZeroPoint());
-  } else {
-    if (!dvo_image_load (&outDB, VERBOSE, TRUE)) {
-      Shutdown ("can't read output image catalog %s", outDB.filename);
-    }
-  }
-
-  // convert database table to internal structure & add to output image db
-  dvo_image_merge_dbs(IDmap, &outDB, &inDB);
-  dvo_image_unlock (&inDB); // unlock input
-
-  SetProtect (TRUE);
-  dvo_image_save (&outDB, VERBOSE);
-  SetProtect (FALSE);
-  dvo_image_unlock (&outDB); // unlock output
-
-  return TRUE;
-}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvomergeUpdate_threaded.c	(revision 30118)
@@ -0,0 +1,313 @@
+# include "dvomerge.h"
+# include <pthread.h>
+
+enum {
+  TS_WAIT,
+  TS_RUN,
+  TS_DONE,
+  TS_FAIL,
+  TS_EXIT,
+};
+
+typedef struct {
+  int iThread;
+  int state;
+  // elements used to carry data to the threadjob
+  char *name;
+  char *filename;
+  SkyRegion *region;
+  int NsecfiltInput;
+  int NsecfiltOutput;
+  IDmapType *IDmap;
+  SkyTable *outsky;
+  int *secfiltMap;
+  int depth;
+} ThreadData;
+
+void *dvomergeUpdate_threadjob (void *inputData) {
+
+  off_t j;
+  Catalog incatalog, outcatalog;
+  SkyList *outlist;
+
+  ThreadData *threadData = (ThreadData *) inputData;
+
+  while (TRUE) {
+
+    while (threadData->state != TS_RUN) {
+      usleep (100);
+    }
+
+    if (VERBOSE) fprintf (stderr, "input: %s\n", threadData->name);
+
+    // load / create output catalog (if catalog does not exist, it will be created)
+    LoadCatalog (&incatalog, threadData->region, threadData->filename, "r", threadData->NsecfiltInput);
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+      dvo_catalog_unlock (&incatalog);
+      dvo_catalog_free (&incatalog);
+      threadData->state = TS_DONE;
+      continue;
+    }
+
+    // combine only tables at equal or larger depth.
+
+    // NOTE: this requirement is especially important for the threaded version: if the
+    // output catalog is guaranteed to be the same size or finer than the input, then two
+    // input catalogs cannot collide on their target output catalog.
+      
+    // load in all of the tables from input for this region
+    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
+    // compare to a slightly reduced footprint
+    float dPos = 2.0/3600.0;
+    outlist = SkyListByBounds (threadData->outsky, threadData->depth, threadData->region->Rmin + dPos, threadData->region->Rmax - dPos, threadData->region->Dmin + dPos, threadData->region->Dmax - dPos);
+    for (j = 0; (j < outlist[0].Nregions) && (threadData->state != TS_FAIL); j++) {
+      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
+
+      // load input catalog
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w", threadData->NsecfiltOutput);
+
+      dvo_update_image_IDs (threadData->IDmap, &incatalog);
+      merge_catalogs_old (&threadData->outsky->regions[j], &outcatalog, &incatalog, RADIUS, threadData->secfiltMap);
+
+      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+      // if we receive a signal which would cause us to exit, wait until the full catalog is written
+      SetProtect (TRUE);
+      if (!dvo_catalog_save (&outcatalog, VERBOSE)) {
+	fprintf (stderr, "ERROR: failed to save catalog %s\n", outlist[0].filename[j]);
+	threadData->state = TS_FAIL;
+	continue;
+      }
+      SetProtect (FALSE);
+
+      dvo_catalog_unlock (&outcatalog);
+      dvo_catalog_free (&outcatalog);
+
+      fprintf (stderr, "merged %s into %s\n", threadData->name, outlist[0].regions[j][0].name);
+    }
+    SkyListFree (outlist);
+
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
+    threadData->state = TS_DONE;
+  }
+  return NULL;
+}
+
+int dvomergeUpdate_threaded (int argc, char **argv) {
+
+  int j, launched, done, Nwait, Nrun;
+
+  ThreadData *threadData;
+  pthread_t *threads;
+
+  int depth, CONTINUE;
+  off_t i, Ns, Ne;
+  SkyTable *outsky, *insky;
+  SkyList *inlist;
+  char filename[256], *input, *output;
+  IDmapType IDmap;
+  PhotCodeData *inputPhotcodes;
+  PhotCodeData *outputPhotcodes;
+  int *secfiltMap = NULL;
+  int NsecfiltInput, NsecfiltOutput;
+
+  double dtime;
+  struct timeval start, stop;
+  gettimeofday (&start, NULL);
+
+  CONTINUE = FALSE;
+  if (strcasecmp (argv[2], "into")) dvomerge_usage();
+  if (argc == 5) {
+    if (strcasecmp (argv[4], "continue")) dvomerge_usage();
+    CONTINUE = TRUE;
+  }
+
+  input  = argv[1];
+  output = argv[3];
+
+  if (ALTERNATE_PHOTCODE_FILE) {
+    fprintf (stderr, "cannot specify photcodes when merging into an existing catdir\n");
+    exit (1);
+  }
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", input);
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
+    fprintf (stderr, "error reading input database directory %s\n", input);
+    exit (1);
+  }	
+  inputPhotcodes = GetPhotcodeTable();
+  NsecfiltInput = GetPhotcodeNsecfilt();
+
+  // since we are merging the input db into the output db, the output defines the photcode
+  // table & db layout but, this requires the output to exist.  if it does not, instead use the
+  // input.
+
+  SetPhotcodeTable(NULL);
+  sprintf (filename, "%s/Photcodes.dat", output);
+  if (LoadPhotcodes (filename, NULL, FALSE)) {
+
+    outputPhotcodes = GetPhotcodeTable();
+    NsecfiltOutput = GetPhotcodeNsecfilt();
+
+    secfiltMap = GetSecFiltMap(outputPhotcodes, inputPhotcodes);
+    if (!secfiltMap) {
+      fprintf (stderr, "failed to map input secfilt photcodes to output photcodes table\n");
+      exit (1);
+    }
+  } else {
+    fprintf(stderr, "%s not found using photcodes from %s/Photcodes.dat\n", filename, input);
+    outputPhotcodes = inputPhotcodes;
+    NsecfiltOutput = NsecfiltInput;
+
+    if (!check_dir_access (output, VERBOSE)) {
+      fprintf (stderr, "error creating output database directory %s\n", output);
+      exit (1);
+    }
+    SetPhotcodeTable(inputPhotcodes);
+    if (!SavePhotcodesFITS (filename)) {
+      fprintf (stderr, "error saving photcode table in %s/Photcodes.dat\n", output);
+      exit (1);
+    }
+  }
+
+  if (CONTINUE) {
+    // need to determine the mapping from the input to the output images
+    dvomergeImagesGetMap (&IDmap, input, output);
+  } else {
+    dvomergeImagesUpdate (&IDmap, input, output);
+  }
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  if (!insky) {
+      Shutdown ("can't read SkyTable for %s", input);
+  }
+  SkyTableSetFilenames (insky, input, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // generate an output table populated at the desired depth
+  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  if (!outsky) {
+      Shutdown ("can't read or create SkyTable for %s", output);
+  }
+  SkyTableSetFilenames (outsky, output, "cpt");
+
+  // loop over the populatable output tables; check for data in input in the corresponding regions
+
+  SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  depth = inlist[0].regions[Ns][0].depth;
+  
+  SetPhotcodeTable(NULL);
+
+  ALLOCATE(threads, pthread_t, NTHREADS);
+  ALLOCATE(threadData, ThreadData, NTHREADS);
+  for (i = 0; i < NTHREADS; i++) {
+    threadData[i].state = TS_WAIT;
+    threadData[i].iThread = i;
+  }
+  for (i = 0; i < NTHREADS; i++) {
+    pthread_create (&threads[i], NULL, &dvomergeUpdate_threadjob, (void *) &threadData[i]);
+  }
+
+  // loop over the populated input regions
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    launched = FALSE;
+    while (!launched) {
+
+      // are any threads done? can we harvest them?
+      for (j = 0; j < NTHREADS; j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_DONE) continue;
+	// fprintf (stderr, "harvested thread %d\n", threadData[j].iThread);
+	threadData[j].state = TS_WAIT;
+      }
+	
+      // are any threads available? can we launch this job?
+      for (j = 0; !launched && (j < NTHREADS); j++) {
+	if (threadData[j].state == TS_FAIL) goto failure;
+	if (threadData[j].state != TS_WAIT) continue;
+
+	threadData[j].name = inlist[0].regions[i][0].name;
+	threadData[j].filename = inlist[0].filename[i];
+	threadData[j].region = inlist[0].regions[i];
+	threadData[j].NsecfiltInput = NsecfiltInput;
+	threadData[j].NsecfiltOutput = NsecfiltOutput;
+	threadData[j].IDmap = &IDmap;
+	threadData[j].outsky = outsky;
+	threadData[j].secfiltMap = secfiltMap;
+	threadData[j].depth = depth;
+	threadData[j].state = TS_RUN;
+	launched = TRUE;
+      }
+      if (!launched) usleep (100);
+    }
+  }
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+    // are any threads done? can we harvest them?
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_DONE) continue;
+      threadData[j].state = TS_WAIT;
+    }
+
+    // how many are waiting now?
+    Nwait = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state == TS_FAIL) goto failure;
+      if (threadData[j].state != TS_WAIT) continue;
+      Nwait ++;
+    }
+
+    if (Nwait < NTHREADS) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+
+  // save the output sky table copy
+  sprintf (filename, "%s/SkyTable.fits", output);
+  check_file_access (filename, TRUE, TRUE, VERBOSE);
+  if (!SkyTableSave (outsky, filename)) {
+    fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
+    exit (1);
+  }
+
+  gettimeofday (&stop, NULL);
+  dtime = DTIME (stop, start);
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec\n", dtime);
+
+  exit (0);
+
+failure:
+
+  // wait for all threads to be done
+  done = FALSE;
+  while (!done) {
+
+    // how many are still running?
+    Nrun = 0;
+    for (j = 0; j < NTHREADS; j++) {
+      if (threadData[j].state != TS_RUN) continue;
+      Nrun ++;
+    }
+
+    if (Nrun) { 
+      usleep (100); 
+    } else {
+      done = TRUE;
+    }
+  }
+  exit (1);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepair.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepair.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepair.c	(revision 30118)
@@ -0,0 +1,14 @@
+# include "dvomerge.h"
+
+int main (int argc, char **argv) {
+
+  dvorepair_help(argc, argv);
+  
+  if (!strcmp(argv[1], "-fix-cpt")) dvorepairFixCPT(argc, argv);
+  // if (!strcmp(argv[1], "-fix-tables")) dvorepairFixTables(argc, argv);
+  if (!strcmp(argv[1], "-images-vs-measures")) dvorepairImagesVsMeasures(argc, argv);
+  if (!strcmp(argv[1], "-delete-image-list")) dvorepairDeleteImageList(argc, argv);
+  if (!strcmp(argv[1], "-fix-images")) dvorepairFixImages(argc, argv);
+  dvorepair_help(0, NULL);
+  exit (2);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairCPT.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairCPT.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairCPT.c	(revision 30118)
@@ -0,0 +1,190 @@
+# include "dvomerge.h"
+
+# define myAbort(MSG) { fprintf (stderr, "%s\n", MSG); abort(); }
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+// broken cpt file, valid cpm file: we can recover everything in the cpt file from the cpm file:
+// * load the full cpm file
+// * loop over detections
+// * if ave_ref is new: create a new object
+//   * determine RA & DEC from ext_id
+//   * obj_id, cat_id are defined in detection
+//   * 
+
+// XXX absorb this code into a unified dvorepair program
+
+int main (int argc, char **argv) {
+
+  off_t Nmeasure, Nimage;
+  int i, Nbytes, NaveMax, Naverage, NAVERAGE, Nave, Nold;
+  int *found;
+
+  Image *image, *thisImage;
+  Average *average;
+  Measure *measure;
+
+  Matrix matrix;
+
+  char *cpmFilename, *cptFilenameSrc, *cptFilenameTgt, *imageFilename;
+
+  Header cptHeaderPHU, cptHeaderTBL;
+  Header cpmHeaderPHU, cpmHeaderTBL;
+  FTable cpmFtable, cptFtable;
+
+  FILE *cptFileSrc = NULL;
+  FILE *cptFileTgt = NULL;
+  FILE *cpmFile = NULL;
+
+  char catformat;
+
+  if (argc != 5) {
+    fprintf (stderr, "USAGE: dvorepair (images) (cpm) (cptInput) (cptOutput)\n");
+    exit (2);
+  }
+
+  imageFilename  = argv[1];
+  cpmFilename    = argv[2];
+  cptFilenameSrc = argv[3];
+  cptFilenameTgt = argv[4];
+
+  cpmFtable.header = &cpmHeaderTBL;
+  cptFtable.header = &cptHeaderTBL;
+
+  // XXX don't bother locking for now: this is totally manual..
+
+  // load the image data
+  if ((image = LoadImages (imageFilename, &Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  // open cpm file
+  cpmFile = fopen(cpmFilename, "r");
+  myAssert(cpmFile, "failed to open cpm file");
+
+  // load the cpm header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+    myAbort("failure to cpm header");
+  }
+
+  // move to TBL header
+  Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+  fseeko (cpmFile, Nbytes, SEEK_SET);
+
+  // read cpm TBL header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+    myAbort("can't read header for cpm table");
+  }
+  // read Measure table data : format is irrelevant here */
+  if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, FALSE)) { 
+    myAbort("can't read data for cpm table");
+  }
+
+  measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+  myAssert(measure, "failed to convert ftable to measure data");
+
+  NaveMax = 0;
+  NAVERAGE = 1000;
+  ALLOCATE (average, Average, NAVERAGE);
+  memset (average, 0, NAVERAGE*sizeof(Average));
+
+  ALLOCATE (found, int, NAVERAGE);
+  memset (found, 0, NAVERAGE*sizeof(int));
+
+  // examine all measurements and new objects as needed
+  for (i = 0; i < Nmeasure; i++) {
+    Nave = measure[i].averef;
+    if (found[Nave]) {
+      average[Nave].Nmeasure ++;
+      myAssert(average[Nave].objID == measure[i].objID, "objIDs do not match!");
+      myAssert(average[Nave].catID == measure[i].catID, "catIDs do not match!");
+      continue;
+    }
+
+    if (Nave >= NAVERAGE) {
+      Nold = NAVERAGE;
+      NAVERAGE = MAX(Nave + 1000, NAVERAGE + 1000);
+      REALLOCATE (average, Average, NAVERAGE);
+      memset (&average[Nold], 0, (NAVERAGE - Nold)*sizeof(Average));
+
+      REALLOCATE (found, int, NAVERAGE);
+      memset (&found[Nold], 0, (NAVERAGE - Nold)*sizeof(int));
+    }
+
+    NaveMax = MAX(Nave, NaveMax);
+
+    found[Nave] = TRUE;
+
+    // we are going to leave most of the elements of average unset: they are the result of 
+    // the relastro analysis for this object and can be recreated with a call to relastro
+
+    // fields we have to set:
+
+    // need to find image so we can use ccd coordinates to determine RA & DEC
+    thisImage = MatchImage (image, Nimage, measure[i].t, measure[i].photcode, measure[i].imageID);
+    XY_to_RD (&average[Nave].R, &average[Nave].D, measure[i].Xccd, measure[i].Yccd, &thisImage[0].coords);
+
+    average[Nave].Nmeasure = 1;
+    average[Nave].Nmissing = 0;
+
+    // assume the resulting table set is unsorted
+    average[Nave].measureOffset = -1;
+    average[Nave].missingOffset = -1;
+    average[Nave].extendOffset = -1;
+
+    average[Nave].objID = measure[i].objID;
+    average[Nave].catID = measure[i].catID;
+    average[Nave].extID = CreatePSPSObjectID(average[Nave].R, average[Nave].D);
+  }
+  Naverage = NaveMax + 1;
+
+  // have we created all objects in the range 0 - Naverage?
+  for (i = 0; i < Naverage; i++) {
+    myAssert(found[i], "failed to find one");
+  }
+
+  // open source cpt file
+  cptFileSrc = fopen(cptFilenameSrc, "r");
+  myAssert(cptFileSrc, "failed to open cpt file");
+
+  // load the cpt header (use for CATID, RA,DEC range, filenames)
+  if (!gfits_fread_header (cptFileSrc, &cptHeaderPHU)) {
+    myAbort("failure to cpt header");
+  }
+
+  // update the output header
+  gfits_modify (&cptHeaderPHU, "NSTARS",     "%d",      1,  Naverage);
+  gfits_modify (&cptHeaderPHU, "NMEAS",      OFF_T_FMT, 1,  Nmeasure);
+  gfits_modify (&cptHeaderPHU, "NMISS",      "%d",      1,  0);
+  gfits_modify_alt (&cptHeaderPHU, "SORTED", "%t",      1,  FALSE);
+
+  /* convert internal to external format */
+  if (!AverageToFtable (&cptFtable, average, Naverage, catformat, NULL)) {
+    myAbort("trouble converting format");
+  }
+
+  // create and write the output file
+  cptFileTgt = fopen(cptFilenameTgt, "w");
+  myAssert(cptFileTgt, "failed to open cpt file");
+    
+  // write PHU header
+  if (!gfits_fwrite_header (cptFileTgt, &cptHeaderPHU)) {
+    myAbort("can't write primary header");
+  }
+
+  // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+  gfits_create_matrix (&cptHeaderPHU, &matrix);
+  if (!gfits_fwrite_matrix  (cptFileTgt, &matrix)) {
+    myAbort("can't write primary matrix");
+  }
+  gfits_free_matrix (&matrix);
+
+  // write the table data
+  if (!gfits_fwrite_ftable_range (cptFileTgt, &cptFtable, 0, Naverage, 0, Naverage)) {
+    myAbort("can't write table data");
+  }
+  
+  fclose(cptFileTgt);
+  fclose(cptFileSrc);
+  fclose(cpmFile);
+
+  exit (0);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairDeleteImageList.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairDeleteImageList.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairDeleteImageList.c	(revision 30118)
@@ -0,0 +1,568 @@
+# include "dvomerge.h"
+
+// delete images based on a text table of the target IDs
+// * load the delete table file (validate format)
+// * load the Images.dat file
+// * create an index for imageID (seq = imageIDindex[i])
+// * create an index of the imageIDs to be deleted (delete (T/F) = imageDELindex[i])
+// * determine the full RA & DEC range of the images to be deleted
+// * scan over all catalog files in the specified RA & DEC range
+// * load the cpm file (pad if short, identify the padded section)
+// * create a new cpm file
+// * loop over detections : only keep those not from images to be deleted
+// * load the cpt file
+// * rebuild the cpt file or delete the matching entries?
+
+int dvorepairDeleteImageList (int argc, char **argv) {
+
+  FITS_DB db;  // database handle pointing to input image table
+
+  off_t i, j, Nmeasure, NmeasureNew, Ndelete, Nvalid, Nimage, Nindex, *imageIdx, index;
+  int N, seq, Nbytes, NbytesPerRow, Ncheck, nPass, raPass;
+  double Rthis, Dthis, Rmin, Rmax, Dmin, Dmax, Qthis, Qmin, Qmax, dR, dQ;
+
+  Image *image;
+  Measure *measure;
+  Measure *measureNew;
+
+  Matrix matrix;
+
+  SkyTable *insky;
+  SkyList *inlist;
+
+  char *cpmFilenameSrc = NULL;
+  char *cptFilenameSrc = NULL;
+  char *cpsFilenameSrc = NULL;
+  char *cpmFilenameTgt = NULL;
+  char *cptFilenameTgt = NULL;
+  char *cpsFilenameTgt = NULL;
+
+  char *imageFilename = NULL;
+
+  Header cpmHeaderPHU;
+  Header cpmHeaderTBL;
+  FTable cpmFtable;
+
+  FILE *cpmFile = NULL;
+
+  char catformat;
+
+  N = get_argument (argc, argv, "-delete-image-list");
+  myAssert(N == 1, "programming error: -delete-image-list must be first from main");
+  remove_argument (N, &argc, argv);
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dvorepair -delete-image-list (catdir) (deleteList)\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    fprintf (stderr, "  deleteList : table from dvorepair giving images to be deleted\n");
+    exit (2);
+  }
+
+  char *catdir = argv[1];
+  char *delList = argv[2];
+
+  // load the image data
+  ALLOCATE(imageFilename, char, strlen(catdir) + 12);
+  sprintf (imageFilename, "%s/Images.dat", catdir);
+  if ((image = LoadImages (&db, imageFilename, &Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  // generate an index for imageIDs
+
+  // find the full range of the imageID values
+  Nindex = 0;
+  for (i = 0; i < Nimage; i++) {
+    Nindex = MAX(image[i].imageID, Nindex);
+  }
+
+  // create the index vector
+  ALLOCATE (imageIdx, off_t, (Nindex + 1));
+  memset (imageIdx, 0, (Nindex + 1)*sizeof(off_t));
+
+  // assign the imageIDs to the index vector
+  for (i = 0; i < Nimage; i++) {
+    index = image[i].imageID;
+    myAssert(index, "image index cannot be 0");
+    myAssert(!imageIdx[index], "stomping on an earlier index");
+    imageIdx[index] = i;
+  }
+
+  // generate an index of the deletion image
+  int *deleteIndex;
+  ALLOCATE (deleteIndex, int, Nindex + 1);
+  memset (deleteIndex, 0, (Nindex + 1)*sizeof(int));
+
+  int NdeleteIDs;
+  int *deleteIDs = ReadDeleteList(delList, &NdeleteIDs);
+
+  for (i = 0; i < NdeleteIDs; i++) {
+    index = deleteIDs[i];
+    myAssert(index > 0, "image index cannot be <= 0");
+    myAssert(index <= Nindex, "delete index out of range of real data");
+    myAssert(!deleteIndex[index], "stomping on an earlier index");
+    deleteIndex[index] = TRUE;
+  }
+
+  // find the RA & DEC range of the images we want to delete
+  Rmin = 360.0; 
+  Rmax = 0.0;
+  Dmin = +90.0;
+  Dmax = -90.0;
+  Qmin = 360.0;
+  Qmax =   0.0;
+  for (i = 0; i < NdeleteIDs; i++) {
+    index = deleteIDs[i];
+    seq = imageIdx[index];
+    if (!FindMosaicForImage (image, Nimage, seq)) {
+      fprintf (stderr, "cannot find mosaic for %s, skipping\n", image[seq].name);
+      continue;
+    }
+
+    XY_to_RD(&Rthis, &Dthis, 0, 0, &image[seq].coords);
+    Rmin = MIN(Rthis, Rmin);
+    Rmax = MAX(Rthis, Rmax);
+    Dmin = MIN(Dthis, Dmin);
+    Dmax = MAX(Dthis, Dmax);
+    Qthis = (Rthis < 180.0) ? Rthis : Rthis - 360.0;
+    Qmin = MIN(Qthis, Qmin);
+    Qmax = MAX(Qthis, Qmax);
+
+    // fprintf (stderr, "image @ %f,%f\n", Rthis, Dthis);
+
+    XY_to_RD(&Rthis, &Dthis, image[seq].NX, 0, &image[seq].coords);
+    Rmin = MIN(Rthis, Rmin);
+    Rmax = MAX(Rthis, Rmax);
+    Dmin = MIN(Dthis, Dmin);
+    Dmax = MAX(Dthis, Dmax);
+    Qthis = (Rthis < 180.0) ? Rthis : Rthis - 360.0;
+    Qmin = MIN(Qthis, Qmin);
+    Qmax = MAX(Qthis, Qmax);
+
+    XY_to_RD(&Rthis, &Dthis, 0, image[seq].NY, &image[seq].coords);
+    Rmin = MIN(Rthis, Rmin);
+    Rmax = MAX(Rthis, Rmax);
+    Dmin = MIN(Dthis, Dmin);
+    Dmax = MAX(Dthis, Dmax);
+    Qthis = (Rthis < 180.0) ? Rthis : Rthis - 360.0;
+    Qmin = MIN(Qthis, Qmin);
+    Qmax = MAX(Qthis, Qmax);
+
+    XY_to_RD(&Rthis, &Dthis, image[seq].NX, image[seq].NY, &image[seq].coords);
+    Rmin = MIN(Rthis, Rmin);
+    Rmax = MAX(Rthis, Rmax);
+    Dmin = MIN(Dthis, Dmin);
+    Dmax = MAX(Dthis, Dmax);
+    Qthis = (Rthis < 180.0) ? Rthis : Rthis - 360.0;
+    Qmin = MIN(Qthis, Qmin);
+    Qmax = MAX(Qthis, Qmax);
+  }
+
+  dQ = Qmax - Qmin;
+  dR = Rmax - Rmin;
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(insky, "can't read SkyTable");
+  SkyTableSetFilenames (insky, catdir, "cpt");
+  
+  // XXX apply this...generate the subset matching the user-selected region
+  SkyRegion UserPatch;
+
+  if (dR < dQ) {
+    fprintf (stderr, "R,D range: %f - %f, %f - %f\n", Rmin, Rmax, Dmin, Dmax);
+    nPass = 1;
+  } else {
+    fprintf (stderr, "R,D range: %f - %f, %f - %f\n", Qmin, Qmax, Dmin, Dmax);
+    nPass = 2;
+  }
+  
+  ALLOCATE(cpmFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cptFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cpsFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cpmFilenameTgt, char, strlen(catdir) + 64);
+  ALLOCATE(cptFilenameTgt, char, strlen(catdir) + 64);
+  ALLOCATE(cpsFilenameTgt, char, strlen(catdir) + 64);
+
+  for (raPass = 0; raPass < nPass; raPass++) {
+    
+    UserPatch.Dmin = Dmin + 0.1;
+    UserPatch.Dmax = Dmax + 0.1;
+
+    if (dR < dQ) {
+      UserPatch.Rmin = Rmin;
+      UserPatch.Rmax = Rmax;
+    } else {
+      if (raPass == 0) {
+	UserPatch.Rmin = 0.0;
+	UserPatch.Rmax = Qmax;
+      } else {
+	UserPatch.Rmin = Qmin + 360.0;
+	UserPatch.Rmax = 360.0;
+      }
+    }
+
+    inlist = SkyListByPatch (insky, -1, &UserPatch);
+  
+    // SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+    // depth = inlist[0].regions[Ns][0].depth;
+  
+    // loop over the populated input regions
+    Ncheck = 0;
+    for (i = 0; i < inlist[0].Nregions; i++) {
+      if (!inlist[0].regions[i][0].table) continue;
+
+      sprintf (cpmFilenameSrc, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
+      sprintf (cptFilenameSrc, "%s/%s.cpt", catdir, inlist[0].regions[i][0].name);
+      sprintf (cpsFilenameSrc, "%s/%s.cps", catdir, inlist[0].regions[i][0].name);
+      sprintf (cpmFilenameTgt, "%s/%s.cpm.fixed", catdir, inlist[0].regions[i][0].name);
+      sprintf (cptFilenameTgt, "%s/%s.cpt.fixed", catdir, inlist[0].regions[i][0].name);
+      sprintf (cpsFilenameTgt, "%s/%s.cps.fixed", catdir, inlist[0].regions[i][0].name);
+      cpmFtable.header = &cpmHeaderTBL;
+
+      /*** read and examine the CPM file ***/
+      {
+	// fprintf (stderr, "check %s\n", cpmFilenameSrc);
+
+	// open cpm file
+	cpmFile = fopen(cpmFilenameSrc, "r");
+	if (!cpmFile) continue;
+	// myAssert(cpmFile, "failed to open cpm file");
+    
+	// load the cpm header
+	if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+	  myAbort("failure to cpm header");
+	}
+
+	// move to TBL header
+	Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+	fseeko (cpmFile, Nbytes, SEEK_SET);
+
+	// read cpm TBL header
+	if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+	  myAbort("can't read header for cpm table");
+	}
+
+	// read Measure table data : format is irrelevant here */
+	if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, TRUE)) { 
+	  myAbort("can't read data for cpm table");
+	}
+
+	gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+
+	measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+	myAssert(measure, "failed to convert ftable to measure data");
+    
+	Nvalid = (int)(cpmFtable.validsize / NbytesPerRow);
+	Nvalid = MIN(Nmeasure, Nvalid);
+
+	// close the input cpm file
+	fclose(cpmFile);
+
+	// allocate an output array of measures (to replace, if needed)
+	ALLOCATE (measureNew, Measure, Nvalid);
+
+	NmeasureNew = 0;
+	Ndelete = 0;
+
+	// examine all measurements: find ones that need to be deleted
+	for (j = 0; j < Nvalid; j++) {
+	  index = measure[j].imageID;
+	  myAssert(index, "measure is missing an image ID");
+
+	  if (deleteIndex[index]) {
+	    Ndelete ++;
+	    continue;
+	  }
+	  measureNew[NmeasureNew] = measure[j];
+	  NmeasureNew ++;
+	}
+      }
+
+      fprintf (stderr, "deleting %d of %d (keep %d) detections from %s -> %s\n", (int) Ndelete, (int) Nvalid, (int) NmeasureNew, cpmFilenameSrc, cpmFilenameTgt);
+
+      // if we actually want to delete any measurements, write out a new cpm file
+      if (Ndelete > 0) {
+
+	// the CPT and CPS tables need to be regenerated.  This must happen first because, in the process, we also update measure->averef
+	RepairTableCPT(cptFilenameSrc, cptFilenameTgt, cpsFilenameSrc, cpsFilenameTgt, measureNew, NmeasureNew, image, Nimage, catformat);
+
+	// convert internal to external format 
+	if (!MeasureToFtable (&cpmFtable, measureNew, NmeasureNew, catformat)) {
+	  myAbort("trouble converting format");
+	}
+
+	// create and write the output file
+	cpmFile = fopen(cpmFilenameTgt, "w");
+	myAssert(cpmFile, "failed to open cpt file");
+	
+	// write PHU header
+	if (!gfits_fwrite_header (cpmFile, &cpmHeaderPHU)) {
+	  myAbort("can't write primary header");
+	}
+
+	// write the PHU matrix; this is probably a NOP, do I have to keep it in?
+	gfits_create_matrix (&cpmHeaderPHU, &matrix);
+	if (!gfits_fwrite_matrix  (cpmFile, &matrix)) {
+	  myAbort("can't write primary matrix");
+	}
+	gfits_free_matrix (&matrix);
+	
+	// write the table data
+	if (!gfits_fwrite_ftable_range (cpmFile, &cpmFtable, 0, NmeasureNew, 0, NmeasureNew)) {
+	  myAbort("can't write table data");
+	}
+	fclose (cpmFile);
+      }
+      gfits_free_header (&cpmHeaderPHU);
+      gfits_free_header (&cpmHeaderTBL);
+      free (measure);
+      free (measureNew);
+
+      Ncheck ++;
+      if (Ncheck % 1000 == 0) {
+	fprintf (stderr, "%s...", inlist[0].regions[i][0].name);
+      }
+    }
+    fprintf (stderr, "\n");
+    SkyListFree(inlist);
+  }
+
+  free (imageFilename);
+  free (imageIdx);
+  free (deleteIndex);
+  free (deleteIDs);
+
+  free(cpmFilenameSrc);
+  free(cptFilenameSrc);
+  free(cpsFilenameSrc);
+  free(cpmFilenameTgt);
+  free(cptFilenameTgt);
+  free(cpsFilenameTgt);
+
+  SkyTableFree(insky);
+
+  exit (0);
+}
+
+int RepairTableCPT(char *cptFilenameSrc, char *cptFilenameTgt, char *cpsFilenameSrc, char *cpsFilenameTgt, Measure *measure, off_t Nmeasure, Image *image, off_t Nimage, char catformat) {
+
+  off_t *averefMatch;
+  off_t i, NaveMax, Naverage, NAVERAGE, NaverageOut, Nave, Nout, Nold;
+  int *found, Nsecfilt;
+
+  Image *thisImage;
+  Average *average, *averageOut;
+
+  Matrix matrix;
+
+  Header cptHeaderPHU;
+  Header cptHeaderTBL;
+  FTable cptFtable;
+
+  FILE *cptFileSrc = NULL;
+  FILE *cptFileTgt = NULL;
+
+  cptFtable.header = &cptHeaderTBL;
+
+  NaveMax = 0;
+  NAVERAGE = 1000;
+  ALLOCATE (average, Average, NAVERAGE);
+  memset (average, 0, NAVERAGE*sizeof(Average));
+
+  ALLOCATE (found, int, NAVERAGE);
+  memset (found, 0, NAVERAGE*sizeof(int));
+
+  // examine all measurements and new objects as needed
+  for (i = 0; i < Nmeasure; i++) {
+    Nave = measure[i].averef;
+
+    if (Nave >= NAVERAGE) {
+      Nold = NAVERAGE;
+      NAVERAGE = MAX(Nave + 1000, NAVERAGE + 1000);
+      REALLOCATE (average, Average, NAVERAGE);
+      memset (&average[Nold], 0, (NAVERAGE - Nold)*sizeof(Average));
+
+      REALLOCATE (found, int, NAVERAGE);
+      memset (&found[Nold], 0, (NAVERAGE - Nold)*sizeof(int));
+    }
+
+    if (found[Nave]) {
+      average[Nave].Nmeasure ++;
+      myAssert(average[Nave].objID == measure[i].objID, "objIDs do not match!");
+      myAssert(average[Nave].catID == measure[i].catID, "catIDs do not match!");
+      continue;
+    }
+
+    NaveMax = MAX(Nave, NaveMax);
+
+    found[Nave] = TRUE;
+
+    // we are going to leave most of the elements of average unset: they are the result of 
+    // the relastro analysis for this object and can be recreated with a call to relastro
+
+    // need to find image so we can use ccd coordinates to determine RA & DEC
+    thisImage = MatchImage (image, Nimage, measure[i].t, measure[i].photcode, measure[i].imageID);
+    XY_to_RD (&average[Nave].R, &average[Nave].D, measure[i].Xccd, measure[i].Yccd, &thisImage[0].coords);
+
+    average[Nave].Nmeasure = 1;
+    average[Nave].Nmissing = 0;
+
+    // assume the resulting table set is unsorted
+    average[Nave].measureOffset = -1;
+    average[Nave].missingOffset = -1;
+    average[Nave].extendOffset = -1;
+
+    average[Nave].objID = measure[i].objID;
+    average[Nave].catID = measure[i].catID;
+    average[Nave].extID = CreatePSPSObjectID(average[Nave].R, average[Nave].D);
+  }
+  Naverage = NaveMax + 1;
+
+  // we now have an average table, but there will be holes due to deleted measurements 
+  // create a new average table with only existing entries
+
+  ALLOCATE (averageOut, Average, Naverage);
+  memset (averageOut, 0, Naverage*sizeof(Average));
+
+  ALLOCATE (averefMatch, off_t, Naverage);
+  memset (averefMatch, 0, Naverage*sizeof(int));
+
+  Nave = 0;
+  for (i = 0; i < Naverage; i++) {
+    if (!found[i]) continue;
+    averageOut[Nave] = average[i]; // use a memcpy?
+    averefMatch[i] = Nave;
+    Nave ++;
+  }
+  NaverageOut = Nave;
+
+  for (i = 0; i < Nmeasure; i++) {
+    Nave = measure[i].averef;
+    Nout = averefMatch[Nave];
+    myAssert(Nout < NaverageOut, "output averef is wrong");
+    
+    myAssert(average[Nave].objID == measure[i].objID, "objIDs do not match");
+    myAssert(average[Nave].catID == measure[i].catID, "objIDs do not match");
+    myAssert(averageOut[Nout].objID == measure[i].objID, "objIDs do not match");
+    myAssert(averageOut[Nout].catID == measure[i].catID, "objIDs do not match");
+
+    measure[i].averef = Nout;
+  }
+
+  fprintf (stderr, "cpt file : %d obj -> %d obj (%s -> %s)\n", (int) Naverage, (int) NaverageOut, cptFilenameSrc, cptFilenameTgt);
+
+  // open source cpt file
+  cptFileSrc = fopen(cptFilenameSrc, "r");
+  myAssert(cptFileSrc, "failed to open cpt file");
+
+  // load the cpt header (use for CATID, RA,DEC range, filenames)
+  if (!gfits_fread_header (cptFileSrc, &cptHeaderPHU)) {
+    myAbort("failure to cpt header");
+  }
+
+  // update the output header
+  gfits_modify (&cptHeaderPHU, "NSTARS",     OFF_T_FMT, 1,  NaverageOut);
+  gfits_modify (&cptHeaderPHU, "NMEAS",      OFF_T_FMT, 1,  Nmeasure);
+  gfits_modify (&cptHeaderPHU, "NMISS",      "%d",      1,  0);
+  gfits_modify_alt (&cptHeaderPHU, "SORTED", "%t",      1,  FALSE);
+
+  gfits_scan (&cptHeaderPHU, "NSECFILT",     "%d",      1,  &Nsecfilt);
+
+  /* convert internal to external format */
+  if (!AverageToFtable (&cptFtable, averageOut, NaverageOut, catformat, NULL)) {
+    myAbort("trouble converting format");
+  }
+
+  // create and write the output file
+  cptFileTgt = fopen(cptFilenameTgt, "w");
+  myAssert(cptFileTgt, "failed to open cpt file");
+    
+  // write PHU header
+  if (!gfits_fwrite_header (cptFileTgt, &cptHeaderPHU)) {
+    myAbort("can't write primary header");
+  }
+
+  // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+  gfits_create_matrix (&cptHeaderPHU, &matrix);
+  if (!gfits_fwrite_matrix  (cptFileTgt, &matrix)) {
+    myAbort("can't write primary matrix");
+  }
+  gfits_free_matrix (&matrix);
+
+  // write the table data
+  if (!gfits_fwrite_ftable_range (cptFileTgt, &cptFtable, 0, NaverageOut, 0, NaverageOut)) {
+    myAbort("can't write table data");
+  }
+  
+  fclose(cptFileTgt);
+  fclose(cptFileSrc);
+
+  gfits_free_header (&cptHeaderPHU);
+  gfits_free_header (&cptHeaderTBL);
+  free (average);
+  free (averageOut);
+
+  free (found);
+  free (averefMatch);
+
+  { 
+    Header cpsHeaderPHU;
+    Header cpsHeaderTBL;
+    FTable cpsFtable;
+
+    FILE *cpsFileSrc = NULL;
+    FILE *cpsFileTgt = NULL;
+
+    SecFilt *secfilt = NULL;
+
+    cpsFtable.header = &cpsHeaderTBL;
+
+    // open source cpt file
+    cpsFileSrc = fopen(cpsFilenameSrc, "r");
+    myAssert(cpsFileSrc, "failed to open cps file");
+    
+    // load the cps header (use for CATID, RA,DEC range, filenames)
+    if (!gfits_fread_header (cpsFileSrc, &cpsHeaderPHU)) {
+      myAbort("failure to cps header");
+    }
+
+    int Nrows = Nsecfilt*NaverageOut;
+    ALLOCATE (secfilt, SecFilt, Nrows);
+
+    /* convert internal to external format */
+    if (!SecFiltToFtable (&cpsFtable, secfilt, Nrows, catformat)) {
+      myAbort("trouble converting format");
+    }
+
+    // create and write the output file
+    cpsFileTgt = fopen(cpsFilenameTgt, "w");
+    myAssert(cpsFileTgt, "failed to open cps file");
+    
+    // write PHU header
+    if (!gfits_fwrite_header (cpsFileTgt, &cpsHeaderPHU)) {
+      myAbort("can't write primary header");
+    }
+
+    // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+    gfits_create_matrix (&cpsHeaderPHU, &matrix);
+    if (!gfits_fwrite_matrix  (cpsFileTgt, &matrix)) {
+      myAbort("can't write primary matrix");
+    }
+    gfits_free_matrix (&matrix);
+
+    // write the table data
+    if (!gfits_fwrite_ftable_range (cpsFileTgt, &cpsFtable, 0, Nrows, 0, Nrows)) {
+      myAbort("can't write table data");
+    }
+  
+    fclose(cpsFileTgt);
+    fclose(cpsFileSrc);
+
+    gfits_free_header (&cpsHeaderPHU);
+    gfits_free_header (&cpsHeaderTBL);
+    free (secfilt);
+  }
+
+  return (TRUE);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixCPT.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixCPT.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixCPT.c	(revision 30118)
@@ -0,0 +1,160 @@
+# include "dvomerge.h"
+
+// broken cpt file, valid cpm file: we can recover everything in the cpt file from the cpm file:
+// * load the full cpm file
+// * loop over detections
+// * if ave_ref is new: create a new object
+//   * determine RA & DEC from ext_id
+//   * obj_id, cat_id are defined in detection
+
+int FixCPTfile (char *rootname, Image *image, off_t Nimage);
+
+int dvorepairFixCPT (int argc, char **argv) {
+
+  int i, j, N, Nfiles, NFILES;
+  off_t Nimage;
+  FITS_DB db;  // database handle pointing to input image table
+  Image *image;
+  char *listFilename, *imageFilename;
+  char **files;
+
+  N = get_argument (argc, argv, "-fix-cpt");
+  myAssert(N == 1, "programming error: -fix-cpt must be first from main");
+  remove_argument (N, &argc, argv);
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dvorepair -fix-cpt (images) (filelist)\n");
+    exit (2);
+  }
+
+  imageFilename  = argv[1];
+  listFilename   = argv[2];
+
+  // XXX don't bother locking for now: this is totally manual..
+
+  // load the image data
+  if ((image = LoadImages (&db, imageFilename, &Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  FILE *file = fopen (listFilename, "r");
+  myAssert(file, "failed to open list");
+
+  Nfiles = 0;
+  NFILES = 100;
+  ALLOCATE(files, char *, NFILES);
+  for (i = 0; i < NFILES; i++) {
+    ALLOCATE (files[i], char, 256);
+    memset (files[i], 0, 256);
+  }
+
+  for (i = 0; TRUE; i++) {
+    if (fscanf (file, "%s", files[i]) == EOF) {
+      break;
+    }
+    if (i == NFILES - 1) {
+      NFILES += 100;
+      REALLOCATE(files, char *, NFILES);
+      for (j = i + 1; j < NFILES; j++) {
+	ALLOCATE (files[j], char, 256);
+	memset (files[j], 0, 256);
+      }
+    }
+  }
+  Nfiles = i;
+  fclose(file);
+  
+  for (i = 0; i < Nfiles; i++) {
+    FixCPTfile(files[i], image, Nimage);
+  }
+
+  exit (0);
+}
+
+// fix the CPT file.  in the process, we rewrite the CPM file so that the averef entries are correctly set.
+int FixCPTfile (char *rootFilename, Image *image, off_t Nimage) {
+
+  char cptFilenameSrc[256], cptFilenameTgt[256], cpsFilenameSrc[256], cpsFilenameTgt[256], cpmFilenameSrc[256], cpmFilenameTgt[256];
+
+  Header cpmHeaderPHU, cpmHeaderTBL;
+  FTable cpmFtable;
+  FILE  *cpmFile = NULL;
+
+  off_t Nbytes, Nmeasure;
+
+  Measure *measure;
+
+  Matrix matrix;
+
+  char catformat;
+
+  cpmFtable.header = &cpmHeaderTBL;
+
+  sprintf (cpmFilenameSrc, "%s.cpm", rootFilename);
+  sprintf (cpmFilenameTgt, "%s.cpm.fixed", rootFilename);
+  sprintf (cptFilenameSrc, "%s.cpt", rootFilename);
+  sprintf (cptFilenameTgt, "%s.cpt.fixed", rootFilename);
+  sprintf (cpsFilenameSrc, "%s.cps", rootFilename);
+  sprintf (cpsFilenameTgt, "%s.cps.fixed", rootFilename);
+
+  // open cpm file
+  cpmFile = fopen(cpmFilenameSrc, "r");
+  myAssert(cpmFile, "failed to open cpm file");
+
+  // load the cpm header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+    myAbort("failure to cpm header");
+  }
+
+  // move to TBL header
+  Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+  fseeko (cpmFile, Nbytes, SEEK_SET);
+
+  // read cpm TBL header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+    myAbort("can't read header for cpm table");
+  }
+  // read Measure table data : format is irrelevant here */
+  // XXX this should not be running on broken CPM files
+  if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, FALSE)) { 
+    myAbort("can't read data for cpm table");
+  }
+
+  measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+  myAssert(measure, "failed to convert ftable to measure data");
+
+  // the CPT and CPS tables need to be regenerated.  This must happen first because, in the process, we also update measure->averef
+  RepairTableCPT(cptFilenameSrc, cptFilenameTgt, cpsFilenameSrc, cpsFilenameTgt, measure, Nmeasure, image, Nimage, catformat);
+
+  // convert internal to external format 
+  if (!MeasureToFtable (&cpmFtable, measure, Nmeasure, catformat)) {
+    myAbort("trouble converting format");
+  }
+
+  // create and write the output file
+  cpmFile = fopen(cpmFilenameTgt, "w");
+  myAssert(cpmFile, "failed to open cpt file");
+	
+  // write PHU header
+  if (!gfits_fwrite_header (cpmFile, &cpmHeaderPHU)) {
+    myAbort("can't write primary header");
+  }
+
+  // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+  gfits_create_matrix (&cpmHeaderPHU, &matrix);
+  if (!gfits_fwrite_matrix  (cpmFile, &matrix)) {
+    myAbort("can't write primary matrix");
+  }
+  gfits_free_matrix (&matrix);
+	
+  // write the table data
+  if (!gfits_fwrite_ftable_range (cpmFile, &cpmFtable, 0, Nmeasure, 0, Nmeasure)) {
+    myAbort("can't write table data");
+  }
+
+  gfits_free_header (&cpmHeaderPHU);
+  gfits_free_header (&cpmHeaderTBL);
+  free (measure);
+  fclose(cpmFile);
+  
+  return TRUE;
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixImages.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixImages.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixImages.c	(revision 30118)
@@ -0,0 +1,289 @@
+# include "dvomerge.h"
+
+// delete images based on a text table of the target IDs
+// * load the delete table file (validate format)
+// * load the Images.dat file
+// * create an index for imageID (seq = imageIDindex[i])
+// * create an index of the imageIDs to be deleted (delete (T/F) = imageDELindex[i])
+// * XXX need to find the DIS images for the WRP images to be deleted 
+// ** BuildChipMatch
+// ** copy ChipMatch, create index
+// ** sort index, ChipMatch by ChipMatch
+// ** loop over ChipMatch, counting delete/no delete for uniq values
+
+void SortChipMatch (off_t *M, off_t *I, off_t N);
+int MarkMosaicsToDelete(Image *image, off_t Nimage, int *deleteIndex);
+
+int dvorepairFixImages (int argc, char **argv) {
+
+  FITS_DB db;  // database handle pointing to input image table
+
+  off_t i, Nimage, Nout, Nindex, *imageIdx, index;
+  
+  int N;
+
+  Image *image, *imageOut;
+
+  char *imageFilenameOld = NULL;
+  char *imageFilenameNew = NULL;
+
+  N = get_argument (argc, argv, "-fix-images");
+  myAssert(N == 1, "programming error: -fix-images must be first from main");
+  remove_argument (N, &argc, argv);
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dvorepair -fix-images (catdir) (deleteList)\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    fprintf (stderr, "  deleteList : table from dvorepair giving images to be deleted\n");
+    exit (2);
+  }
+
+  char *catdir = argv[1];
+  char *delList = argv[2];
+
+  // load the image data
+  ALLOCATE(imageFilenameOld, char, strlen(catdir) + 12);
+  sprintf (imageFilenameOld, "%s/Images.dat", catdir);
+
+  ALLOCATE(imageFilenameNew, char, strlen(catdir) + 24);
+  sprintf (imageFilenameNew, "%s/Images.dat.fixed", catdir);
+
+  if ((image = LoadImages (&db, imageFilenameOld, &Nimage)) == NULL) {
+    fprintf (stderr, "error loading images\n");
+    exit (1);
+  }
+  BuildChipMatch (image, Nimage);
+
+  // generate an index for imageIDs
+
+  // find the full range of the imageID values
+  Nindex = 0;
+  for (i = 0; i < Nimage; i++) {
+    Nindex = MAX(image[i].imageID, Nindex);
+  }
+
+  // create the index vector
+  ALLOCATE (imageIdx, off_t, (Nindex + 1));
+  memset (imageIdx, 0, (Nindex + 1)*sizeof(off_t));
+
+  // assign the imageIDs to the index vector
+  for (i = 0; i < Nimage; i++) {
+    index = image[i].imageID;
+    myAssert(index, "image index cannot be 0");
+    myAssert(!imageIdx[index], "stomping on an earlier index");
+    imageIdx[index] = i;
+  }
+
+  // generate an index of the deletion image
+  int *deleteIndex;
+  ALLOCATE (deleteIndex, int, Nindex + 1);
+  memset (deleteIndex, 0, (Nindex + 1)*sizeof(int));
+
+  int NdeleteIDs;
+  int *deleteIDs = ReadDeleteList(delList, &NdeleteIDs);
+
+  for (i = 0; i < NdeleteIDs; i++) {
+    index = deleteIDs[i];
+    myAssert(index > 0, "image index cannot be <= 0");
+    myAssert(index <= Nindex, "delete index out of range of real data");
+    myAssert(!deleteIndex[index], "stomping on an earlier index");
+    deleteIndex[index] = TRUE;
+  }
+
+  MarkMosaicsToDelete(image, Nimage, deleteIndex);
+
+  // now create a new output Image table with only the non-deletions
+  ALLOCATE (imageOut, Image, Nimage);
+  
+  Nout = 0;
+  for (i = 0; i < Nimage; i++) {
+    index = image[i].imageID;
+    if (deleteIndex[index]) continue;
+    imageOut[Nout] = image[i];
+    Nout++;
+  }
+
+  SaveImages(&db, imageFilenameNew, imageOut, Nout);
+
+  free (imageFilenameOld);
+  free (imageFilenameNew);
+  free (imageIdx);
+  free (deleteIndex);
+  free (deleteIDs);
+
+  exit (0);
+}
+
+// sort two times vectors and an index by first time vector
+void SortChipMatch (off_t *M, off_t *I, off_t N) {
+
+# define SWAPFUNC(A,B){ off_t tmp_m; off_t tmp_i;	\
+    tmp_m = M[A]; M[A] = M[B]; M[B] = tmp_m;		\
+    tmp_i = I[A]; I[A] = I[B]; I[B] = tmp_i;		\
+  }
+# define COMPARE(A,B)(M[A] < M[B])
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+# undef SWAPFUNC
+# undef COMPARE
+}
+
+int MarkMosaicsToDelete(Image *image, off_t Nimage, int *deleteIndex) {
+
+  off_t i;
+  
+  off_t *ChipByMosaicID, *ChipIndex, *mosaicIDs;
+  off_t mosaic, Nmosaic, NMOSAIC, chipSeq, chipID, mosaicID;
+  int *nChildren, *nToDelete;
+  int Na, Nb, Nc;
+
+  /* We now have a table of images to delete by image ID : but only WRP images have been
+     marked.  Now find all WRP images for which none/some/all images are to be deleted.
+  */
+
+  // make a copy of the ChipMatch table (generated by BuildChipMatch, see libdvo/src/mosaic_astrom.c) 
+  // generate an associated image index and sort by the mosaic IDs (value of ChipMatch table)
+  ALLOCATE(ChipByMosaicID, off_t, Nimage);
+  off_t *ChipMatchRaw = GetChipMatch();
+  myAssert(ChipMatchRaw, "need to run BuildChipMatch first");
+
+  memcpy (ChipByMosaicID, ChipMatchRaw, sizeof(off_t)*Nimage);
+  ALLOCATE (ChipIndex, off_t, Nimage);
+  for (i = 0; i < Nimage; i++) {
+    ChipIndex[i] = i;
+  }
+  SortChipMatch(ChipByMosaicID, ChipIndex, Nimage);
+
+  // now count the number of children images with none/some/all marked for deletion
+  // we don't know the number of mosaic images, so allocate as we go
+
+  Nmosaic = 0;
+  NMOSAIC = 1000;
+  ALLOCATE (nChildren, int,   NMOSAIC); memset(&nChildren[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(int));
+  ALLOCATE (nToDelete, int,   NMOSAIC); memset(&nToDelete[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(int));
+  ALLOCATE (mosaicIDs, off_t, NMOSAIC); memset(&mosaicIDs[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(off_t));
+
+  // scan past the mosaic (-3), unassigned (-2) and non-chip (-1) entries 
+  for (i = 0; (i < Nimage) && (ChipByMosaicID[i] == -3); i++);
+  Na = i;
+  fprintf (stderr, "skipping %d DIS entries\n", Na);
+
+  for (; (i < Nimage) && (ChipByMosaicID[i] == -2); i++);
+  Nb = i - Na;
+  fprintf (stderr, "skipping %d failed entries\n", Nb);
+  
+  for (; (i < Nimage) && (ChipByMosaicID[i] == -1); i++);
+  Nc = i - Na - Nb;
+  fprintf (stderr, "skipping %d single-chip entries\n", Nc);
+  
+  if (i == Nimage) {
+    fprintf (stderr, "there are no mosaic images in this database\n");
+    free (nChildren);
+    free (nToDelete);
+    free (mosaicIDs);
+    
+    free (ChipIndex);
+    free (ChipByMosaicID);
+    
+    return TRUE;
+  }
+
+  // mosaicIDs[] actually contains the sequence in images[] of the mosaic images
+  // do not confuse the sequence numbers and the imageID values
+
+  mosaic = ChipByMosaicID[i];
+  mosaicIDs[Nmosaic] = mosaic;
+  for (; i < Nimage; i++) {
+    if (ChipByMosaicID[i] != mosaic) {
+      // time for the next entry
+      Nmosaic ++;
+      if (Nmosaic == NMOSAIC - 1) {
+	NMOSAIC += 1000;
+	REALLOCATE (nChildren, int,   NMOSAIC); memset(&nChildren[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(int));
+	REALLOCATE (nToDelete, int,   NMOSAIC); memset(&nToDelete[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(int));
+	REALLOCATE (mosaicIDs, off_t, NMOSAIC); memset(&mosaicIDs[Nmosaic], 0, (NMOSAIC-Nmosaic)*sizeof(off_t));
+      }
+      mosaic = ChipByMosaicID[i];
+      mosaicIDs[Nmosaic] = mosaic;
+    }
+    nChildren[Nmosaic] ++;
+    chipSeq = ChipIndex[i];
+    chipID = image[chipSeq].imageID;
+    if (deleteIndex[chipID]) {
+      nToDelete[Nmosaic] ++;
+    }
+  }
+  Nmosaic ++;
+
+  // XXX test:
+  for (i = 0; i < Nmosaic; i++) {
+    if (nToDelete[i]) {
+      fprintf (stderr, "mosaic %lld (%lld) : %s : %d children : %d to delete\n",
+	       (long long) i, (long long) mosaicIDs[i], image[mosaicIDs[i]].name, nChildren[i], nToDelete[i]);
+    }
+
+    // mark the mosaic for deletion IFF all children are to be deleted
+    if (nToDelete[i] == nChildren[i]) {
+      mosaic = mosaicIDs[i];
+      mosaicID = image[mosaic].imageID;
+      deleteIndex[mosaicID] = TRUE;
+    }	    
+  }
+
+  free (nChildren);
+  free (nToDelete);
+  free (mosaicIDs);
+
+  free (ChipIndex);
+  free (ChipByMosaicID);
+
+  return TRUE;
+}
+
+int SaveImages(FITS_DB *oldDB, char *filename, Image *imageOut, off_t Nout) {
+
+  int status, Nx, nbytes;
+  off_t IDstart;
+  FITS_DB db;
+
+  /* setup image table format and lock */
+  db.mode   = oldDB->mode;
+  db.format = oldDB->format;
+  status    = dvo_image_lock (&db, filename, 3600.0, LCK_XCLD);  // shorter timeout?
+  if (!status) {
+    fprintf (stderr, "ERROR: failure to lock image catalog %s\n", db.filename);
+    exit (1);
+  }
+
+  /* load or create the image table */
+  myAssert (db.dbstate == LCK_EMPTY, "do not overwrite exiting image table");
+  myAssert (db.format == DVO_FORMAT_PS1_V2, "format mismatch");
+
+  dvo_image_create (&db, GetZeroPoint());
+  
+  // replace the existing buffer with the image array
+  gfits_scan (db.ftable.header, "NAXIS1", "%d", 1,  &Nx);
+  gfits_modify (db.ftable.header, "NAXIS2",  OFF_T_FMT, 1, Nout);
+  db.ftable.header[0].Naxis[1] = Nout;
+
+  nbytes = gfits_data_size (db.ftable.header);
+  db.ftable.datasize = nbytes;
+  db.ftable.buffer = (char *) imageOut;
+  REALLOCATE (db.ftable.buffer, char, MAX (nbytes, 1));
+  memset (&db.ftable.buffer[Nx*Nout], ' ', nbytes - Nx*Nout);
+
+  db.swapped = TRUE; // internal representation
+
+  gfits_modify (&db.header, "NIMAGES", OFF_T_FMT, 1,  Nout);
+
+  status = gfits_scan (&oldDB->header, "IMAGEID", OFF_T_FMT, 1, &IDstart);
+  myAssert(status, "db image table lacks IMAGEID");
+
+  gfits_modify (&db.header, "IMAGEID", OFF_T_FMT, 1,  IDstart);
+
+  dvo_image_save (&db, TRUE);
+
+  dvo_image_unlock (&db);
+
+  return TRUE;
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixTables.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixTables.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairFixTables.c	(revision 30118)
@@ -0,0 +1,423 @@
+# include "dvomerge.h"
+
+// repair short cpm files, fix inconsistent cpt / cps / cpm files
+// * scan over all catalog files in the specified RA & DEC range
+// * load the cpm file (pad if short, identify the padded section)
+// * create a new cpm file
+// * loop over detections : only keep those not from images to be deleted
+// * load the cpt file
+// * rebuild the cpt file or delete the matching entries?
+
+int dvorepairDeleteImageList (int argc, char **argv) {
+
+  FITS_DB db;  // database handle pointing to input image table
+
+  off_t i, j, Nmeasure, NmeasureNew, Ndelete, Nvalid, Nimage, Nindex, *imageIdx, index;
+  int N, seq, Nbytes, NbytesPerRow, Ncheck, nPass, raPass;
+  double Rthis, Dthis, Rmin, Rmax, Dmin, Dmax, Qthis, Qmin, Qmax, dR, dQ;
+
+  Measure *measure;
+  Measure *measureNew;
+
+  SkyTable *insky;
+  SkyList *inlist;
+
+  char *cpmFilenameSrc = NULL;
+  char *cptFilenameSrc = NULL;
+  char *cpsFilenameSrc = NULL;
+  char *cpmFilenameTgt = NULL;
+  char *cptFilenameTgt = NULL;
+  char *cpsFilenameTgt = NULL;
+
+  Header cpmHeaderPHU;
+  Header cpmHeaderTBL;
+  FTable cpmFtable;
+
+  FILE *cpmFile = NULL;
+
+  char catformat;
+
+  N = get_argument (argc, argv, "-fix-tables");
+  myAssert(N == 1, "programming error: -fix-tables must be first from main");
+  remove_argument (N, &argc, argv);
+
+  // restrict to a 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);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: dvorepair -fix-tables (catdir) [-region Rmin Rmax Dmin Dmax]\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    exit (2);
+  }
+
+  char *catdir = argv[1];
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(insky, "can't read SkyTable");
+  SkyTableSetFilenames (insky, catdir, "cpt");
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+  
+  ALLOCATE(cpmFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cptFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cpsFilenameSrc, char, strlen(catdir) + 64);
+  ALLOCATE(cpmFilenameTgt, char, strlen(catdir) + 64);
+  ALLOCATE(cptFilenameTgt, char, strlen(catdir) + 64);
+  ALLOCATE(cpsFilenameTgt, char, strlen(catdir) + 64);
+
+  // loop over the tables
+  Ncheck = 0;
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    sprintf (cpmFilenameSrc, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
+    sprintf (cptFilenameSrc, "%s/%s.cpt", catdir, inlist[0].regions[i][0].name);
+    sprintf (cpsFilenameSrc, "%s/%s.cps", catdir, inlist[0].regions[i][0].name);
+    sprintf (cpmFilenameTgt, "%s/%s.cpm.fixed", catdir, inlist[0].regions[i][0].name);
+    sprintf (cptFilenameTgt, "%s/%s.cpt.fixed", catdir, inlist[0].regions[i][0].name);
+    sprintf (cpsFilenameTgt, "%s/%s.cps.fixed", catdir, inlist[0].regions[i][0].name);
+    cpmFtable.header = &cpmHeaderTBL;
+
+    measure = LoadTableCPM(cpmFilenameSrc, &Nmeasure, &Nexpect);
+
+    // the CPT and CPS tables need to be regenerated.  This must happen first because, in the process, we also update measure->averef
+    RepairTableCPT(cptFilenameSrc, cptFilenameTgt, cpsFilenameSrc, cpsFilenameTgt, measureNew, NmeasureNew, image, Nimage, catformat);
+
+    // if the file is short, create
+    if (Nmeasure != Nexpect) { 
+      fprintf (stderr, "deleting %d of %d (keep %d) detections from %s -> %s\n", (int) Ndelete, (int) Nvalid, (int) NmeasureNew, cpmFilenameSrc, cpmFilenameTgt);
+
+      // convert internal to external format 
+      if (!MeasureToFtable (&cpmFtable, measureNew, NmeasureNew, catformat)) {
+	myAbort("trouble converting format");
+      }
+
+      // create and write the output file
+      cpmFile = fopen(cpmFilenameTgt, "w");
+      myAssert(cpmFile, "failed to open cpt file");
+	
+      // write PHU header
+      if (!gfits_fwrite_header (cpmFile, &cpmHeaderPHU)) {
+	myAbort("can't write primary header");
+      }
+
+      // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+      gfits_create_matrix (&cpmHeaderPHU, &matrix);
+      if (!gfits_fwrite_matrix  (cpmFile, &matrix)) {
+	myAbort("can't write primary matrix");
+      }
+      gfits_free_matrix (&matrix);
+	
+      // write the table data
+      if (!gfits_fwrite_ftable_range (cpmFile, &cpmFtable, 0, NmeasureNew, 0, NmeasureNew)) {
+	myAbort("can't write table data");
+      }
+      fclose (cpmFile);
+    }
+    gfits_free_header (&cpmHeaderPHU);
+    gfits_free_header (&cpmHeaderTBL);
+    free (measure);
+    free (measureNew);
+
+    Ncheck ++;
+    if (Ncheck % 1000 == 0) {
+      fprintf (stderr, "%s...", inlist[0].regions[i][0].name);
+    }
+  }
+  SkyListFree(inlist);
+  SkyTableFree(insky);
+
+  free(cpmFilenameSrc);
+  free(cptFilenameSrc);
+  free(cpsFilenameSrc);
+  free(cpmFilenameTgt);
+  free(cptFilenameTgt);
+  free(cpsFilenameTgt);
+
+  exit (0);
+}
+
+// load this CPM file : is it short?
+Measure *LoadTableCPM (char *cpmFilenameSrc, off_t *nmeasure, off_t *nexpect) {
+
+  fprintf (stderr, "check %s\n", cpmFilenameSrc);
+
+  // open cpm file
+  cpmFile = fopen(cpmFilenameSrc, "r");
+  if (!cpmFile) continue;
+    
+  // load the cpm header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+    myAbort("failure to cpm header");
+  }
+
+  // move to TBL header
+  Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+  fseeko (cpmFile, Nbytes, SEEK_SET);
+
+  // read cpm TBL header
+  if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+    myAbort("can't read header for cpm table");
+  }
+
+  // read Measure table data : format is irrelevant here */
+  if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, TRUE)) { 
+    myAbort("can't read data for cpm table");
+  }
+
+  gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+  gfits_scan(&cpmHeaderTBL, "NAXIS2", "%d", 1, &Nrows);
+
+  measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+  myAssert(measure, "failed to convert ftable to measure data");
+    
+  Nvalid = (int)(cpmFtable.validsize / NbytesPerRow);
+  Nvalid = MIN(Nmeasure, Nvalid);
+
+  // close the input cpm file
+  fclose(cpmFile);
+
+  myAssert(Nrows >= Nvalid, "how can we find more entries than expected??");
+
+  *nmeasure = Nvalid;
+  *nexpect = Nrows;
+
+  return measure;
+}
+
+int RepairTableCPT(char *cptFilenameSrc, char *cptFilenameTgt, char *cpsFilenameSrc, char *cpsFilenameTgt, Measure *measure, off_t Nmeasure, Image *image, off_t Nimage, char catformat) {
+
+  off_t *averefMatch;
+  off_t i, NaveMax, Naverage, NAVERAGE, NaverageOut, Nave, Nout, Nold;
+  int *found, Nsecfilt;
+
+  Image *thisImage;
+  Average *average, *averageOut;
+
+  Matrix matrix;
+
+  Header cptHeaderPHU;
+  Header cptHeaderTBL;
+  FTable cptFtable;
+
+  FILE *cptFileSrc = NULL;
+  FILE *cptFileTgt = NULL;
+
+  cptFtable.header = &cptHeaderTBL;
+
+  NaveMax = 0;
+  NAVERAGE = 1000;
+  ALLOCATE (average, Average, NAVERAGE);
+  memset (average, 0, NAVERAGE*sizeof(Average));
+
+  ALLOCATE (found, int, NAVERAGE);
+  memset (found, 0, NAVERAGE*sizeof(int));
+
+  // examine all measurements and new objects as needed
+  for (i = 0; i < Nmeasure; i++) {
+    Nave = measure[i].averef;
+
+    if (Nave >= NAVERAGE) {
+      Nold = NAVERAGE;
+      NAVERAGE = MAX(Nave + 1000, NAVERAGE + 1000);
+      REALLOCATE (average, Average, NAVERAGE);
+      memset (&average[Nold], 0, (NAVERAGE - Nold)*sizeof(Average));
+
+      REALLOCATE (found, int, NAVERAGE);
+      memset (&found[Nold], 0, (NAVERAGE - Nold)*sizeof(int));
+    }
+
+    if (found[Nave]) {
+      average[Nave].Nmeasure ++;
+      myAssert(average[Nave].objID == measure[i].objID, "objIDs do not match!");
+      myAssert(average[Nave].catID == measure[i].catID, "catIDs do not match!");
+      continue;
+    }
+
+    NaveMax = MAX(Nave, NaveMax);
+
+    found[Nave] = TRUE;
+
+    // we are going to leave most of the elements of average unset: they are the result of 
+    // the relastro analysis for this object and can be recreated with a call to relastro
+
+    // need to find image so we can use ccd coordinates to determine RA & DEC
+    thisImage = MatchImage (image, Nimage, measure[i].t, measure[i].photcode, measure[i].imageID);
+    XY_to_RD (&average[Nave].R, &average[Nave].D, measure[i].Xccd, measure[i].Yccd, &thisImage[0].coords);
+
+    average[Nave].Nmeasure = 1;
+    average[Nave].Nmissing = 0;
+
+    // assume the resulting table set is unsorted
+    average[Nave].measureOffset = -1;
+    average[Nave].missingOffset = -1;
+    average[Nave].extendOffset = -1;
+
+    average[Nave].objID = measure[i].objID;
+    average[Nave].catID = measure[i].catID;
+    average[Nave].extID = CreatePSPSObjectID(average[Nave].R, average[Nave].D);
+  }
+  Naverage = NaveMax + 1;
+
+  // we now have an average table, but there will be holes due to deleted measurements 
+  // create a new average table with only existing entries
+
+  ALLOCATE (averageOut, Average, Naverage);
+  memset (averageOut, 0, Naverage*sizeof(Average));
+
+  ALLOCATE (averefMatch, off_t, Naverage);
+  memset (averefMatch, 0, Naverage*sizeof(int));
+
+  Nave = 0;
+  for (i = 0; i < Naverage; i++) {
+    if (!found[i]) continue;
+    averageOut[Nave] = average[i]; // use a memcpy?
+    averefMatch[i] = Nave;
+    Nave ++;
+  }
+  NaverageOut = Nave;
+
+  for (i = 0; i < Nmeasure; i++) {
+    Nave = measure[i].averef;
+    Nout = averefMatch[Nave];
+    myAssert(Nout < NaverageOut, "output averef is wrong");
+    
+    myAssert(average[Nave].objID == measure[i].objID, "objIDs do not match");
+    myAssert(average[Nave].catID == measure[i].catID, "objIDs do not match");
+    myAssert(averageOut[Nout].objID == measure[i].objID, "objIDs do not match");
+    myAssert(averageOut[Nout].catID == measure[i].catID, "objIDs do not match");
+
+    measure[i].averef = Nout;
+  }
+
+  fprintf (stderr, "cpt file : %d obj -> %d obj (%s -> %s)\n", (int) Naverage, (int) NaverageOut, cptFilenameSrc, cptFilenameTgt);
+
+  // open source cpt file
+  cptFileSrc = fopen(cptFilenameSrc, "r");
+  myAssert(cptFileSrc, "failed to open cpt file");
+
+  // load the cpt header (use for CATID, RA,DEC range, filenames)
+  if (!gfits_fread_header (cptFileSrc, &cptHeaderPHU)) {
+    myAbort("failure to cpt header");
+  }
+
+  // update the output header
+  gfits_modify (&cptHeaderPHU, "NSTARS",     OFF_T_FMT, 1,  NaverageOut);
+  gfits_modify (&cptHeaderPHU, "NMEAS",      OFF_T_FMT, 1,  Nmeasure);
+  gfits_modify (&cptHeaderPHU, "NMISS",      "%d",      1,  0);
+  gfits_modify_alt (&cptHeaderPHU, "SORTED", "%t",      1,  FALSE);
+
+  gfits_scan (&cptHeaderPHU, "NSECFILT",     "%d",      1,  &Nsecfilt);
+
+  /* convert internal to external format */
+  if (!AverageToFtable (&cptFtable, averageOut, NaverageOut, catformat, NULL)) {
+    myAbort("trouble converting format");
+  }
+
+  // create and write the output file
+  cptFileTgt = fopen(cptFilenameTgt, "w");
+  myAssert(cptFileTgt, "failed to open cpt file");
+    
+  // write PHU header
+  if (!gfits_fwrite_header (cptFileTgt, &cptHeaderPHU)) {
+    myAbort("can't write primary header");
+  }
+
+  // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+  gfits_create_matrix (&cptHeaderPHU, &matrix);
+  if (!gfits_fwrite_matrix  (cptFileTgt, &matrix)) {
+    myAbort("can't write primary matrix");
+  }
+  gfits_free_matrix (&matrix);
+
+  // write the table data
+  if (!gfits_fwrite_ftable_range (cptFileTgt, &cptFtable, 0, NaverageOut, 0, NaverageOut)) {
+    myAbort("can't write table data");
+  }
+  
+  fclose(cptFileTgt);
+  fclose(cptFileSrc);
+
+  gfits_free_header (&cptHeaderPHU);
+  gfits_free_header (&cptHeaderTBL);
+  free (average);
+  free (averageOut);
+
+  free (found);
+  free (averefMatch);
+
+  { 
+    Header cpsHeaderPHU;
+    Header cpsHeaderTBL;
+    FTable cpsFtable;
+
+    FILE *cpsFileSrc = NULL;
+    FILE *cpsFileTgt = NULL;
+
+    SecFilt *secfilt = NULL;
+
+    cpsFtable.header = &cpsHeaderTBL;
+
+    // open source cpt file
+    cpsFileSrc = fopen(cpsFilenameSrc, "r");
+    myAssert(cpsFileSrc, "failed to open cps file");
+    
+    // load the cps header (use for CATID, RA,DEC range, filenames)
+    if (!gfits_fread_header (cpsFileSrc, &cpsHeaderPHU)) {
+      myAbort("failure to cps header");
+    }
+
+    int Nrows = Nsecfilt*NaverageOut;
+    ALLOCATE (secfilt, SecFilt, Nrows);
+
+    /* convert internal to external format */
+    if (!SecFiltToFtable (&cpsFtable, secfilt, Nrows, catformat)) {
+      myAbort("trouble converting format");
+    }
+
+    // create and write the output file
+    cpsFileTgt = fopen(cpsFilenameTgt, "w");
+    myAssert(cpsFileTgt, "failed to open cps file");
+    
+    // write PHU header
+    if (!gfits_fwrite_header (cpsFileTgt, &cpsHeaderPHU)) {
+      myAbort("can't write primary header");
+    }
+
+    // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+    gfits_create_matrix (&cpsHeaderPHU, &matrix);
+    if (!gfits_fwrite_matrix  (cpsFileTgt, &matrix)) {
+      myAbort("can't write primary matrix");
+    }
+    gfits_free_matrix (&matrix);
+
+    // write the table data
+    if (!gfits_fwrite_ftable_range (cpsFileTgt, &cpsFtable, 0, Nrows, 0, Nrows)) {
+      myAbort("can't write table data");
+    }
+  
+    fclose(cpsFileTgt);
+    fclose(cpsFileSrc);
+
+    gfits_free_header (&cpsHeaderPHU);
+    gfits_free_header (&cpsHeaderTBL);
+    free (secfilt);
+  }
+
+  return (TRUE);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImageVsMeasure.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImageVsMeasure.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImageVsMeasure.c	(revision 30118)
@@ -0,0 +1,178 @@
+# include "dvomerge.h"
+
+# define myAbort(MSG) { fprintf (stderr, "%s\n", MSG); abort(); }
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+// find images which are missing detections:
+// * load the Images.dat file
+// * create an index for imageID (seq = imageIDindex[i])
+// * scan over all catalog files
+// * load the cpm file (pad if short, identify the padded section)
+// * loop over detections: increment detection count for each imageID
+
+int main (int argc, char **argv) {
+
+  off_t i, j, Nmeasure, Nvalid, Nimage, Nindex, *imageIdx, index, imageSeq;
+  int Nbytes, NbytesPerRow, Nbad, Ncheck, Ntol;
+  int *detCounts;
+
+  Image *image;
+  Measure *measure;
+
+  SkyTable *insky;
+  SkyList *inlist;
+
+  char *catdir = NULL;
+  char *cpmFilename = NULL;
+  char *imageFilename = NULL;
+
+  Header cpmHeaderPHU;
+  Header cpmHeaderTBL;
+  FTable cpmFtable;
+
+  FILE *cpmFile = NULL;
+
+  char catformat;
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dvorepair (catdir) (Ntol)\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    fprintf (stderr, "  Ntol : allow Ntol missing detections\n");
+    exit (2);
+  }
+
+  catdir = argv[1];
+  Ntol = atoi(argv[2]);
+
+  // load the image data
+  ALLOCATE(imageFilename, char, strlen(catdir) + 12);
+  sprintf (imageFilename, "%s/Images.dat", catdir);
+  if ((image = LoadImages (imageFilename, &Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  // generate an index for imageIDs:
+  Nindex = 0;
+  for (i = 0; i < Nimage; i++) {
+    Nindex = MAX(image[i].imageID, Nindex);
+  }
+  ALLOCATE (imageIdx, off_t, (Nindex + 1));
+  memset (imageIdx, 0, (Nindex + 1)*sizeof(off_t));
+
+  for (i = 0; i < Nimage; i++) {
+    index = image[i].imageID;
+    if (index == 0) {
+      fprintf (stderr, "?");
+      continue;
+    }
+    if (imageIdx[index]) {
+      fprintf (stderr, "!");
+      continue;
+    }
+    imageIdx[index] = i;
+  }
+
+  // generate a list of the detection counts:
+  ALLOCATE (detCounts, int, Nimage);
+  memset (detCounts, 0, Nimage*sizeof(int));
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(insky, "can't read SkyTable");
+  SkyTableSetFilenames (insky, catdir, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  SkyRegion UserPatch;
+  UserPatch.Rmin = 0.0;
+  UserPatch.Rmax = 360.0;
+  UserPatch.Dmin = -90.0;
+  UserPatch.Dmax = +90.0;
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  // depth = inlist[0].regions[Ns][0].depth;
+  
+  ALLOCATE(cpmFilename, char, strlen(catdir) + 64);
+
+  // loop over the populated input regions
+  Ncheck = 0;
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    if (1) {
+      sprintf (cpmFilename, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
+      cpmFtable.header = &cpmHeaderTBL;
+
+      // open cpm file
+      cpmFile = fopen(cpmFilename, "r");
+      if (!cpmFile) continue;
+      // myAssert(cpmFile, "failed to open cpm file");
+    
+      // fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
+
+      // load the cpm header
+      if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+	myAbort("failure to cpm header");
+      }
+
+      // move to TBL header
+      Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+      fseeko (cpmFile, Nbytes, SEEK_SET);
+
+      // read cpm TBL header
+      if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+	myAbort("can't read header for cpm table");
+      }
+
+      // read Measure table data : format is irrelevant here */
+      if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, TRUE)) { 
+	myAbort("can't read data for cpm table");
+      }
+
+      gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+
+      measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+      myAssert(measure, "failed to convert ftable to measure data");
+    
+      Nvalid = (int)(cpmFtable.validsize / NbytesPerRow);
+      Nvalid = MIN(Nmeasure, Nvalid);
+
+      // examine all measurements and new objects as needed
+      for (j = 0; j < Nvalid; j++) {
+	index = measure[j].imageID;
+	if (!index) {
+	  fprintf (stderr, "?");
+	  continue;
+	}
+
+	imageSeq = imageIdx[index];
+	// XXX check the range?
+
+	detCounts[imageSeq] ++;
+      }
+      fclose(cpmFile);
+      gfits_free_header (&cpmHeaderPHU);
+      gfits_free_header (&cpmHeaderTBL);
+      free (measure);
+
+      Ncheck ++;
+      if (Ncheck % 1000 == 0) {
+	fprintf (stderr, "%s...", inlist[0].regions[i][0].name);
+      }
+    }
+  }
+  fprintf (stderr, "\n");
+
+  Nbad = 0;
+  for (i = 0; i < Nimage; i++) {
+    // careful: off_t math does not do well with subtractions...
+    if (detCounts[i] + Ntol < image[i].nstar) {
+      fprintf (stdout, "image %s (%d) : %d vs %d\n", image[i].name, image[i].imageID, detCounts[i], image[i].nstar);
+      Nbad ++;
+    }
+  }
+  if (!Nbad) {
+    fprintf (stderr, "no bad images found\n");
+  }
+
+  exit (0);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImagesVsMeasures.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImagesVsMeasures.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvorepairImagesVsMeasures.c	(revision 30118)
@@ -0,0 +1,181 @@
+# include "dvomerge.h"
+
+// find images which are missing detections:
+// * load the Images.dat file
+// * create an index for imageID (seq = imageIDindex[i])
+// * scan over all catalog files
+// * load the cpm file (pad if short, identify the padded section)
+// * loop over detections: increment detection count for each imageID
+
+int dvorepairImagesVsMeasures (int argc, char **argv) {
+
+  FITS_DB db;  // database handle pointing to input image table
+
+  off_t i, j, Nmeasure, Nvalid, Nimage, Nindex, *imageIdx, index, imageSeq;
+  int N, Nbytes, NbytesPerRow, Nbad, Ncheck, Ntol;
+  int *detCounts;
+
+  Image *image;
+  Measure *measure;
+
+  SkyTable *insky;
+  SkyList *inlist;
+
+  char *catdir = NULL;
+  char *cpmFilename = NULL;
+  char *imageFilename = NULL;
+
+  Header cpmHeaderPHU;
+  Header cpmHeaderTBL;
+  FTable cpmFtable;
+
+  FILE *cpmFile = NULL;
+
+  char catformat;
+
+  N = get_argument (argc, argv, "-images-vs-measures");
+  myAssert(N == 1, "programming error: -images-vs-measures must be first from main");
+  remove_argument (N, &argc, argv);
+
+  if (argc != 3) {
+    fprintf (stderr, "USAGE: dvorepair -images-vs-measures (catdir) (Ntol)\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    fprintf (stderr, "  Ntol : allow Ntol missing detections\n");
+    exit (2);
+  }
+
+  catdir = argv[1];
+  Ntol = atoi(argv[2]);
+
+  // load the image data
+  ALLOCATE(imageFilename, char, strlen(catdir) + 12);
+  sprintf (imageFilename, "%s/Images.dat", catdir);
+  if ((image = LoadImages (&db, imageFilename, &Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+
+  // generate an index for imageIDs:
+  Nindex = 0;
+  for (i = 0; i < Nimage; i++) {
+    Nindex = MAX(image[i].imageID, Nindex);
+  }
+  ALLOCATE (imageIdx, off_t, (Nindex + 1));
+  memset (imageIdx, 0, (Nindex + 1)*sizeof(off_t));
+
+  for (i = 0; i < Nimage; i++) {
+    index = image[i].imageID;
+    if (index == 0) {
+      fprintf (stderr, "?");
+      continue;
+    }
+    if (imageIdx[index]) {
+      fprintf (stderr, "!");
+      continue;
+    }
+    imageIdx[index] = i;
+  }
+
+  // generate a list of the detection counts:
+  ALLOCATE (detCounts, int, Nimage);
+  memset (detCounts, 0, Nimage*sizeof(int));
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(insky, "can't read SkyTable");
+  SkyTableSetFilenames (insky, catdir, "cpt");
+
+  // XXX apply this...generate the subset matching the user-selected region
+  SkyRegion UserPatch;
+  UserPatch.Rmin = 0.0;
+  UserPatch.Rmax = 360.0;
+  UserPatch.Dmin = -90.0;
+  UserPatch.Dmax = +90.0;
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
+  // SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  // depth = inlist[0].regions[Ns][0].depth;
+  
+  ALLOCATE(cpmFilename, char, strlen(catdir) + 64);
+
+  // loop over the populated input regions
+  Ncheck = 0;
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    if (1) {
+      sprintf (cpmFilename, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
+      cpmFtable.header = &cpmHeaderTBL;
+
+      // open cpm file
+      cpmFile = fopen(cpmFilename, "r");
+      if (!cpmFile) continue;
+      // myAssert(cpmFile, "failed to open cpm file");
+    
+      // fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
+
+      // load the cpm header
+      if (!gfits_fread_header (cpmFile, &cpmHeaderPHU)) {
+	myAbort("failure to cpm header");
+      }
+
+      // move to TBL header
+      Nbytes = cpmHeaderPHU.datasize + gfits_data_size (&cpmHeaderPHU);
+      fseeko (cpmFile, Nbytes, SEEK_SET);
+
+      // read cpm TBL header
+      if (!gfits_fread_header (cpmFile, &cpmHeaderTBL)) { 
+	myAbort("can't read header for cpm table");
+      }
+
+      // read Measure table data : format is irrelevant here */
+      if (!gfits_fread_ftable_data (cpmFile, &cpmFtable, TRUE)) { 
+	myAbort("can't read data for cpm table");
+      }
+
+      gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+
+      measure = FtableToMeasure (&cpmFtable, &Nmeasure, &catformat);
+      myAssert(measure, "failed to convert ftable to measure data");
+    
+      Nvalid = (int)(cpmFtable.validsize / NbytesPerRow);
+      Nvalid = MIN(Nmeasure, Nvalid);
+
+      // examine all measurements and new objects as needed
+      for (j = 0; j < Nvalid; j++) {
+	index = measure[j].imageID;
+	if (!index) {
+	  fprintf (stderr, "?");
+	  continue;
+	}
+
+	imageSeq = imageIdx[index];
+	// XXX check the range?
+
+	detCounts[imageSeq] ++;
+      }
+      fclose(cpmFile);
+      gfits_free_header (&cpmHeaderPHU);
+      gfits_free_header (&cpmHeaderTBL);
+      free (measure);
+
+      Ncheck ++;
+      if (Ncheck % 1000 == 0) {
+	fprintf (stderr, "%s...", inlist[0].regions[i][0].name);
+      }
+    }
+  }
+  fprintf (stderr, "\n");
+
+  Nbad = 0;
+  for (i = 0; i < Nimage; i++) {
+    // careful: off_t math does not do well with subtractions...
+    if (detCounts[i] + Ntol < image[i].nstar) {
+      fprintf (stdout, "image %s (%d) : %d vs %d\n", image[i].name, image[i].imageID, detCounts[i], image[i].nstar);
+      Nbad ++;
+    }
+  }
+  if (!Nbad) {
+    fprintf (stderr, "no bad images found\n");
+  }
+
+  exit (0);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoverify.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/dvoverify.c	(revision 30118)
@@ -8,170 +8,210 @@
 */
 
+int VerifyTableFile (char *filename);
+
+# define DEBUG 0
+
 int main (int argc, char **argv) {
 
-  char filename[256], *input, *output;
-
-  int depth;
-  off_t i, j, Ns, Ne;
-  SkyTable *outsky, *insky;
+  char filename[1024];
+
+  int N, Nbad;
+  off_t i;
+  SkyTable *insky;
   SkyList *inlist;
-  Catalog incatalog, outcatalog;
-
-  SetSignals ();
-  dvoconvert_help (argc, argv);
-  ConfigInit (&argc, argv);
-  dvoconvert_args (&argc, argv);
-
-  if (strcasecmp (argv[2], "to")) dvoconvert_usage();
-  input = argv[1];
-  output = argv[3];
-
-  // load input images, save to output images
-  dvoConvert_copy_images (input, output);
-
-  // copy photcode table
-  { 
-    // the first input defines the photcode table & db layout
-    sprintf (filename, "%s/Photcodes.dat", input);
-    if (!LoadPhotcodes (filename, NULL, FALSE)) {
-      fprintf (stderr, "error loading photcode table %s\n", filename);
-      exit (1);
-    }
-    // save the photcodes in the output catdir
-    sprintf (filename, "%s/Photcodes.dat", output);
-    if (!check_file_access (filename, TRUE, TRUE, VERBOSE)) {
-      fprintf (stderr, "error creating output catdir %s\n", output);
-      exit (1);
-    }
-    if (!SavePhotcodesFITS (filename)) {
-      fprintf (stderr, "error saving photcode table %s\n", filename);
-      exit (1);
-    }
-  }
-
-  // copy skytable
-  { 
-    // load the sky table for the existing database
-    insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
-    SkyTableSetFilenames (insky, input, "cpt");
-
-    // generate an output table populated at the desired depth
-    // XXX force this to match the input?
-    outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
-    SkyTableSetFilenames (outsky, output, "cpt");
-
-    SkyTablePopulatedRange (&Ns, &Ne, insky, 0);
-    depth = insky[0].regions[Ns].depth;
-    // XXX this seems to imply that insky is a uniform depth...
-  }
-
-  // loop over all input catalogs, save to output catalogs
-  // loop over the populatable output regions
-  for (i = 0; i < outsky[0].Nregions; i++) {
-    if (!outsky[0].regions[i].table) continue;
-    if (VERBOSE) fprintf (stderr, "output: %s\n", outsky[0].regions[i].name);
-
-    // load / create output catalog
-    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w");
-
-    // combine only tables at equal or larger depth
-      
-    // load in all of the tables from input for this region
-    inlist = SkyListByBounds (insky, depth, outsky[0].regions[i].Rmin, outsky[0].regions[i].Rmax, outsky[0].regions[i].Dmin, outsky[0].regions[i].Dmax);
-    for (j = 0; j < inlist[0].Nregions; j++) {
-      if (VERBOSE) fprintf (stderr, "input : %s\n", inlist[0].regions[j][0].name);
-
-      // load input catalog
-      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");
-
-      // skip empty input catalogs
-      if (!incatalog.Naves_disk) {
-	dvo_catalog_unlock (&incatalog);
-	dvo_catalog_free (&incatalog);
-	continue;
-      }
-      merge_catalogs_new (&outsky[0].regions[i], &outcatalog, &incatalog);
-      dvo_catalog_unlock (&incatalog);
-      dvo_catalog_free (&incatalog);
-    }
-    SkyListFree (inlist);
-
-    outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
-    dvo_catalog_save (&outcatalog, VERBOSE);
-    dvo_catalog_unlock (&outcatalog);
-    dvo_catalog_free (&outcatalog);
-  }
-
-  // save the output sky table copy
-  sprintf (filename, "%s/SkyTable.fits", output);
-  check_file_access (filename, TRUE, TRUE, VERBOSE);
-  if (!SkyTableSave (outsky, filename)) {
-    fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
+  SkyRegion UserPatch;
+  // Catalog catalog;
+
+  // restrict to a 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);
+  }
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: dvoverify (catdir) [-region Rmin Rmax Dmin Dmax]\n");
+    fprintf (stderr, "  catdir : database of interest\n");
+    exit (2);
+  }
+
+  char *catdir = argv[1];
+
+  Nbad = 0;
+
+  // XXX make this step optional
+  if (1) {
+    // check the photcode table
+    sprintf (filename, "%s/Photcodes.dat", catdir);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+
+    // check the skytable
+    sprintf (filename, "%s/SkyTable.fits", catdir);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+
+    // check the image table
+    sprintf (filename, "%s/Images.dat", catdir);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+  }
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (catdir, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  myAssert(insky, "can't read SkyTable");
+  SkyTableSetFilenames (insky, catdir, "cpt");
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+  
+  // loop over all catalogs, save to output catalogs
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+
+    if (i % 1000 == 0) fprintf (stderr, ".");
+
+    sprintf (filename, "%s/%s.cpt", catdir, inlist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+
+    sprintf (filename, "%s/%s.cps", catdir, inlist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+
+    sprintf (filename, "%s/%s.cpm", catdir, inlist[0].regions[i][0].name);
+    if (!VerifyTableFile (filename)) {
+      Nbad ++;
+    }
+  }
+
+  if (Nbad > 0) {
+    fprintf (stderr, "ERROR: %d files are bad\n", Nbad);
     exit (1);
   }
 
+  fprintf (stderr, "SUCCESS: no files are bad\n");
   exit (0);
 }
 
-int dvoConvert_copy_images (char *input, char *output) {
-
-  FITS_DB inDB;
-  FITS_DB outDB;
-  int    status;
-
-  Image *images;
-  off_t Nimages;
-  off_t ID;
-
-  /*** load output/Images.dat ***/
-  sprintf (ImageCat, "%s/Images.dat", output);
-  outDB.mode   = dvo_catalog_catmode (CATMODE);
-  outDB.format = dvo_catalog_catformat (CATFORMAT);
-  status       = dvo_image_lock (&outDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
-  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", outDB.filename);
-
-  // output image table should not already exist
-  if (outDB.dbstate != LCK_EMPTY) {
-    Shutdown ("ERROR: image table %s already exists", outDB.filename);
-  }
-  dvo_image_create (&outDB, GetZeroPoint());
-
-  /*** load input/Images.dat ***/
-  sprintf (ImageCat, "%s/Images.dat", input);
-  // inDB.mode   = dvo_catalog_catmode (CATMODE);
-  // inDB.format = dvo_catalog_catformat (CATFORMAT);
-  status       = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
-  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", inDB.filename);
-
-  // load the image table 
-  if (inDB.dbstate == LCK_EMPTY) {
-    Shutdown ("can't find input image catalog %s", inDB.filename);
-  }
-  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
-    Shutdown ("can't read input image catalog %s", inDB.filename);
-  }
-
-  // convert the raw image table to Image type (byteswap if needed)
-  images = gfits_table_get_Image (&inDB.ftable, &Nimages, &inDB.swapped);
-  if (!images) {
-    fprintf (stderr, "ERROR: failed to read images\n");
-    exit (2);
-  }
-
-  // update additional metadata
-  gfits_scan (&inDB.header, "IMAGEID", OFF_T_FMT, 1,  &ID);
-  gfits_modify (&outDB.header, "NIMAGES", OFF_T_FMT, 1,  Nimages);
-  gfits_modify (&outDB.header, "IMAGEID", OFF_T_FMT, 1,  ID);
-
-  // copy input rows to output table
-  gfits_add_rows (&outDB.ftable, (char *) images, Nimages, sizeof(Image));
-
-  // write out the image table to disk
-  SetProtect (TRUE);
-  dvo_image_save (&outDB, VERBOSE);
-  SetProtect (FALSE);
-  dvo_image_unlock (&outDB); // unlock output
-  dvo_image_unlock (&inDB); // unlock input1
-
+// is this file a consistent FITS file?
+int VerifyTableFile (char *filename) {
+
+  int status;
+  off_t Nbytes;
+  Header header;
+
+  struct stat fileStats;
+  FILE *file;
+
+  // does the file exist?
+  status = stat (filename, &fileStats);
+  if (status) {
+    // some error accessing the file.  there is only one acceptable error: file not found
+    switch (errno) {
+      case ENOENT:
+	if (DEBUG) fprintf (stderr, "file does not exist, skipping %s\n", filename);
+	return TRUE;
+      case ENOMEM:
+	fprintf (stderr, "Out of memory: %s\n", filename);
+	return TRUE;
+      case EACCES:
+	fprintf (stderr, "Permission error on %s\n", filename);
+	return FALSE;
+      case EFAULT:
+	fprintf (stderr, "Bad address: %s\n", filename);
+	return FALSE;
+      case ELOOP:
+	fprintf (stderr, "Too many symbolic links encountered while traversing the path: %s\n", filename);
+	return FALSE;
+      case ENAMETOOLONG:
+	fprintf (stderr, "File name too long: %s\n", filename);
+	return FALSE;
+      case ENOTDIR:
+	fprintf (stderr, "A component of the path is not a directory: %s\n", filename);
+	return FALSE;
+      case EOVERFLOW:
+	fprintf (stderr, "file too large for program version: %s\n", filename);
+	return FALSE;
+      default:
+	fprintf (stderr, "unknown error: %s\n", filename);
+	return FALSE;
+    }
+  }
+
+  // does it have any data?
+  if (fileStats.st_size == 0) {
+    fprintf (stderr, "file is empty: %s\n", filename);
+    return FALSE;
+  }
+
+  // can we open it?
+  file = fopen(filename, "r");
+  if (!file) {
+    fprintf (stderr, "unable to open valid file: %s\n", filename);
+    return FALSE;
+  }
+
+  // scan all extentions
+  Nbytes = 0;
+  if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
+  while (Nbytes < fileStats.st_size) {
+
+    // Check on the PHU
+    if (!gfits_fread_header (file, &header)) {
+      fprintf (stderr, "unable to read PHU header for %s\n", filename);
+      fclose(file);
+      return (FALSE);
+    }
+
+    // move to TBL header
+    Nbytes += header.datasize + gfits_data_size (&header);
+    if (DEBUG) fprintf (stderr, "sizes: ("OFF_T_FMT" vs "OFF_T_FMT")\n", Nbytes, fileStats.st_size);
+    if (Nbytes > fileStats.st_size) {
+      fprintf (stderr, "file is short ("OFF_T_FMT" vs "OFF_T_FMT"): %s\n", Nbytes, fileStats.st_size, filename);
+      gfits_free_header(&header);
+      fclose (file);
+      return FALSE;
+    }
+    gfits_free_header(&header);
+
+    status = fseeko (file, Nbytes, SEEK_SET);
+    if (status) {
+      switch (errno) {
+	case EBADF:
+	  fprintf (stderr, "something wrong with file handle: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+	case EINVAL:
+	  fprintf (stderr, "invalid offset: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+	default:
+	  fprintf (stderr, "other error in fseeko: %s\n", filename);
+	  fclose (file);
+	  return FALSE;
+      }
+    }
+  }
+  if (DEBUG) fprintf (stderr, "file is good: %s\n", filename);
+  fclose (file);
   return TRUE;
 }
+
+  // gfits_scan(&cpmHeaderTBL, "NAXIS1", "%d", 1, &NbytesPerRow);
+  // gfits_scan(&cpmHeaderTBL, "NAXIS2", "%d", 1, &Nrows);
+    
+  
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/help.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/help.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/help.c	(revision 30118)
@@ -4,4 +4,6 @@
   fprintf (stderr, "USAGE: dvomerge (input1) and (input2) to (output)\n");
   fprintf (stderr, "   OR: dvomerge (input) into (output)\n");
+  fprintf (stderr, "   OR: dvomerge (input) into (output) continue\n");
+  fprintf (stderr, "   OR: dvomerge (input) into (output) from (list)\n");
   fprintf (stderr, "   [-region Rmin Rmax Dmin Dmax]\n");
   exit (2);
@@ -17,5 +19,5 @@
 void dvosecfilt_usage(void) {
 
-  fprintf (stderr, "USAGE: dvosecfilt (input) -photcodes (photcodes.txt)\n");
+  fprintf (stderr, "USAGE: dvosecfilt (catdir) (Nsecfilt)\n");
 
   exit (2);
@@ -33,5 +35,7 @@
   fprintf (stderr, "USAGE\n");
   fprintf (stderr, "  dvomerge (input1) and (input2) to (output)\n");
-  fprintf (stderr, "  dvomerge (input) into (output)\n\n");
+  fprintf (stderr, "  dvomerge (input) into (output)\n");
+  fprintf (stderr, "  dvomerge (input) into (output) continue\n\n");
+  fprintf (stderr, "  dvomerge (input) into (output) from (list)\n\n");
   fprintf (stderr, "  merge DVO databases\n");
   fprintf (stderr, "  optional flags:\n");
@@ -39,4 +43,5 @@
   fprintf (stderr, "  -help                 	  : this list\n");
   fprintf (stderr, "  -h                    	  : this list\n\n");
+  fprintf (stderr, "  -region Rmin Rmax Dmin Dmax : region to merge\n\n");
   exit (2);
 }
@@ -75,7 +80,8 @@
 
   fprintf (stderr, "USAGE\n");
-  fprintf (stderr, "  dvosecfilt (input) (Nsecfilt)\n\n");
+  fprintf (stderr, "  dvosecfilt (catdir) (Nsecfilt)\n\n");
 
-  fprintf (stderr, "  change number of secfilt entries in photcode table (updates secfilt tables only)\n");
+  fprintf (stderr, "  change number of secfilt entries in photcode table (updates secfilt tables (cps), NSECFILT in cpt files)\n");
+  fprintf (stderr, "  NOTE: the user must change the photcode table to reflect the change (use photcode-table -export / -import)\n");
  
   fprintf (stderr, "  optional flags:\n");
@@ -86,2 +92,26 @@
 }
 
+void dvorepair_help (int argc, char **argv) {
+
+  /* check for help request */
+  if (!argv) goto show_help;
+  if (get_argument (argc, argv, "-help")) goto show_help;
+  if (get_argument (argc, argv, "-h"))    goto show_help;
+  if (argc < 2) goto show_help;
+  return;
+
+show_help:
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  dvorepair -fix-cpt (images) (rootlist) - regenerate cpt & cps files from the cpm files\n");
+  fprintf (stderr, "  dvorepair -images-vs-measures (catdir) (Ntol) - find images with too many missing detections\n");
+  fprintf (stderr, "  dvorepair -delete-image-list (catdir) (deleteList) - delete a set of images based on image IDs (output from -images-vs-measures)\n");
+  fprintf (stderr, "  dvorepair -fix-images (catdir) (deleteList) - delete a set of images based on image IDs (output from -images-vs-measures)\n");
+  fprintf (stderr, "\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
+
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/match_image.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/match_image.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/match_image.c	(revision 30118)
@@ -0,0 +1,37 @@
+# include "dvomerge.h"
+
+off_t match_image (Image *image, off_t Nimage, unsigned int T, short int S) {
+
+  off_t N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[N].tzero == T) && (image[N].photcode == S)) {
+      return (N);
+    }
+  }
+  return (-1);
+}
Index: /branches/czw_branch/20101203/Ohana/src/dvomerge/src/merge_catalogs_old.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/dvomerge/src/merge_catalogs_old.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/dvomerge/src/merge_catalogs_old.c	(revision 30118)
@@ -28,5 +28,5 @@
   unsigned int objID, catID;
   Coords tcoords;
-
+  
   // struct timeval start, stop;
   // gettimeofday (&start, (void *) NULL);
@@ -240,4 +240,6 @@
     } else {
       for (k = 0; k < NsecfiltIn; k++) {
+	if (secfiltMap[k] < 0) continue;  // skip secfilt entries from input that are not in the output
+
         // index for this entry in output's secfilt list
         int outputIndex = n * NsecfiltOut + secfiltMap[k];
@@ -254,5 +256,5 @@
     i++;
   }
-  // MARKTIME("find matched stars: %f sec for "OFF_T_FMT","OFF_T_FMT" stars\n", dtime, Nstars, Nave);
+  // MARKTIME("find matched stars: %f sec for "OFF_T_FMT","OFF_T_FMT" stars ("OFF_T_FMT" meas)\n", dtime, Nstars, Nave, Nmeas);
 
   /** incorporate unmatched image stars, if this star is in field of this catalog **/
Index: /branches/czw_branch/20101203/Ohana/src/imregister/imphot/rfits.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/imregister/imphot/rfits.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/imregister/imphot/rfits.c	(revision 30118)
@@ -17,5 +17,5 @@
     return (FALSE);
   }
-  if (!gfits_fread_ftable_data (db[0].f, &db[0].ftable)) {
+  if (!gfits_fread_ftable_data (db[0].f, &db[0].ftable, FALSE)) {
     fprintf (stderr, "can't read table data");
     return (FALSE);
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/Makefile
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/Makefile	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/Makefile	(revision 30118)
@@ -42,4 +42,5 @@
 $(SRC)/bDrawObjects.$(ARCH).o	  	  $(SRC)/bDrawFrame.$(ARCH).o         \
 $(SRC)/bDrawLabels.$(ARCH).o              $(SRC)/bDrawIt.$(ARCH).o            \
+$(SRC)/bDrawImage.$(ARCH).o               \
 $(SRC)/PNGit.$(ARCH).o                    $(SRC)/PPMit.$(ARCH).o	      \
 $(SRC)/PSit.$(ARCH).o                     $(SRC)/CrossHairs.$(ARCH).o         \
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/include/prototypes.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/include/prototypes.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/include/prototypes.h	(revision 30118)
@@ -40,10 +40,11 @@
 void          DrawYErrors         PROTO((KapaGraphWidget *graph, Gobjects *objects));
 void	      DrawTick		  PROTO((Graphic *graphic, Axis *axis, int P, TickMarkData *tick, int naxis));
-void	      AxisTickScale	  PROTO((Axis *axis, double *major, double *minor));
+void	      AxisTickScale	  PROTO((Axis *axis, double *major, double *minor, int *nsignif));
 TickMarkData *CreateAxisTicks     PROTO((Axis *axis, int *nticks));
-int           PrintTick           PROTO((char *string, double value, double min, double max));
+int           PrintTick           PROTO((char *string, double value, double min, double max, int nsignif));
 
 /* EventLoop */
 int           PScommand           PROTO((int sock));
+int           PNGcommand          PROTO((int sock));
 int           CheckPipe           PROTO((void));
 int           Reconfig            PROTO((XEvent *event));
@@ -52,5 +53,5 @@
 
 /* CheckPipe */
-int           PNGit               PROTO((int sock));
+int           PNGit               PROTO((char *filename));
 int           PPMit               PROTO((int sock));
 int           LoadFrame           PROTO((int sock));
@@ -67,4 +68,5 @@
 int           MoveSection         PROTO((int sock));
 int           DefineSection       PROTO((int sock));
+int           DefineSectionByImage PROTO((int sock));
 int           SetFont             PROTO((int sock));
 int           EraseCurrentPlot    PROTO((void));
@@ -126,17 +128,18 @@
 
 /* kapa bDraw Functions */
-int	      bDrawFrame	  PROTO((KapaGraphWidget *graph));
-int	      bDrawObjects	  PROTO((KapaGraphWidget *graph));
-void	      bDrawLabels	  PROTO((KapaGraphWidget *graph));
-void	      bDrawTextlines	  PROTO((KapaGraphWidget *graph));
-void	      bDrawConnect	  PROTO((KapaGraphWidget *graph, Gobjects *object));
-void	      bDrawHistogram	  PROTO((KapaGraphWidget *graph, Gobjects *object));
-void	      bDrawPoints	  PROTO((KapaGraphWidget *graph, Gobjects *object));
-void	      bDrawXErrors	  PROTO((KapaGraphWidget *graph, Gobjects *object));
-void	      bDrawYErrors	  PROTO((KapaGraphWidget *graph, Gobjects *object));
-void	      bDrawTick		  PROTO((Axis *axis, int P, TickMarkData *tick, int naxis));
-void	      bDrawClipLine	  PROTO((double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0));
-bDrawBuffer  *bDrawIt		  PROTO((void));
-void          bDrawGraph          PROTO((KapaGraphWidget *graph));
+int	      bDrawFrame	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+int	      bDrawObjects	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+void	      bDrawLabels	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+void	      bDrawTextlines	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+void	      bDrawConnect	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
+void	      bDrawHistogram	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
+void	      bDrawPoints	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
+void	      bDrawXErrors	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
+void	      bDrawYErrors	  PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object));
+void	      bDrawTick		  PROTO((bDrawBuffer *buffer, Axis *axis, int P, TickMarkData *tick, int naxis));
+void	      bDrawClipLine	  PROTO((bDrawBuffer *buffer, double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0));
+void          bDrawGraph          PROTO((bDrawBuffer *buffer, KapaGraphWidget *graph));
+int           bDrawImage          PROTO((bDrawBuffer *buffer, KapaImageWidget *image, Graphic *graphic));
+bDrawBuffer  *bDrawIt		  PROTO((png_color *palette, int Npalette, int Nbyte));
 
 /* misc support */
@@ -212,4 +215,6 @@
 int	      Overlay3		  PROTO((Graphic *graphic, KapaImageWidget *image));
 int	      PSfunction	  PROTO((Graphic *graphic, KapaImageWidget *image));
+int	      PNGfunction	  PROTO((Graphic *graphic, KapaImageWidget *image));
+int	      JPEGfunction	  PROTO((Graphic *graphic, KapaImageWidget *image));
 
 /* misc functions */
@@ -219,5 +224,6 @@
 int  	      SaveOverlay  (int sock);
 int  	      CSaveOverlay (int sock);
-int  	      JPEGit24     (int sock);
+int  	      JPEGit24     (char *filename);
+int  	      JPEGcommand  (int sock);
 
 int  	      UpdatePointer (Graphic *graphic, XMotionEvent *event);
@@ -241,5 +247,5 @@
 int  	      GetActiveSocket (void);
 void 	      InvertButton (Graphic *graphic, Button *button);
-void 	      bDrawOverlay (KapaImageWidget *image, int N);
+void 	      bDrawOverlay (bDrawBuffer *buffer, KapaImageWidget *image, int N);
 
 /* color cube tools */
@@ -261,2 +267,5 @@
 int SetColorScale3D_CC (Graphic *graphic, KapaImageWidget *image);
 int SetColorCubeHistogram (void);
+int GetGraphBoundary (Section *section, double *x0, double *y0, double *x1, double *y1, int *dXm, int *dXp, int *dYm, int *dYp);
+int ResizeByImage (int sock);
+
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/include/structures.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/include/structures.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/include/structures.h	(revision 30118)
@@ -148,4 +148,5 @@
   int IsMajor;
   int IsLabel;
+  int nsignif;
 } TickMarkData;
 
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/ButtonFunctions.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 30118)
@@ -7,4 +7,20 @@
 
   status = PSit ("kapa.ps", "default", TRUE, KAPA_PS_NEWPLOT);
+  return (status);
+}
+
+int PNGfunction (Graphic *graphic, KapaImageWidget *image) {
+
+  int status;
+
+  status = PNGit ("kapa.png");
+  return (status);
+}
+
+int JPEGfunction (Graphic *graphic, KapaImageWidget *image) {
+
+  int status;
+
+  status = JPEGit24 ("kapa.jpg");
   return (status);
 }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/CheckPipe.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/CheckPipe.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/CheckPipe.c	(revision 30118)
@@ -89,9 +89,15 @@
   
   if (!strcmp (word, "PNGF")) {
-    status = PNGit (sock);
-    KiiSendCommand (sock, 4, "DONE");
-    FINISHED (status);
-  }
-  
+    status = PNGcommand (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+  
+  if (!strcmp (word, "JPEG")) {
+    status = JPEGcommand (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+
   if (!strcmp (word, "PPMF")) {
     status = PPMit (sock);
@@ -131,4 +137,10 @@
   }
 
+  if (!strcmp (word, "ISIZ")) {
+    status = ResizeByImage (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (TRUE);
+  }
+  
   if (!strcmp (word, "MOVE")) {
     status = Relocate (sock);
@@ -211,4 +223,10 @@
   if (!strcmp (word, "DSEC")) {
     status = DefineSection (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (TRUE);
+  }
+  
+  if (!strcmp (word, "ISEC")) {
+    status = DefineSectionByImage (sock);
     KiiSendCommand (sock, 4, "DONE");
     FINISHED (TRUE);
@@ -300,10 +318,4 @@
   if (!strcmp (word, "CSVE")) {
     status = CSaveOverlay (sock);
-    KiiSendCommand (sock, 4, "DONE");
-    FINISHED (status);
-  }
-
-  if (!strcmp (word, "JPEG")) {
-    status = JPEGit24 (sock);
     KiiSendCommand (sock, 4, "DONE");
     FINISHED (status);
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/DefineSection.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/DefineSection.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/DefineSection.c	(revision 30118)
@@ -40,2 +40,58 @@
   return (TRUE);
 }
+
+// define the section, but do not create a graph or image 
+int DefineSectionByImage (int sock) {
+  
+  int N, bg;
+  char name[128];
+  double x, y, dx, dy;
+  int dXm, dXp, dYm, dYp;
+  double x0, y0, x1, y1, expand;
+  Section *section;
+  Graphic *graphic;
+  KapaImageWidget *image;
+
+  KiiScanMessage (sock, "%s %lf %lf %d", name, &x, &y, &bg);
+
+  N = GetSectionByName (name);
+  section = GetSectionByNumber (N);
+  image = section->image;
+  if (!image) {
+    fprintf (stderr, "no image to define section\n");
+    return (TRUE);
+  }
+  SetActiveSectionByNumber (N);
+
+  graphic = GetGraphic ();
+
+  GetGraphBoundary (section, &x0, &y0, &x1, &y1, &dXm, &dXp, &dYm, &dYp);
+
+  expand = 1.0;
+  if (image[0].picture.expand > 0) {
+    expand = image[0].picture.expand;
+  }
+  if (image[0].picture.expand < 0) {
+    expand = 1.0 / fabs((double)image[0].picture.expand);
+  }
+
+  // pixel dimensions of the imaging region + boundary
+  dx = image[0].image[0].matrix.Naxis[0]*expand + x1;
+  dy = image[0].image[0].matrix.Naxis[1]*expand + y1;
+
+  section[0].x = x;
+  section[0].y = y;
+  section[0].bg = bg;
+  section[0].dx = dx / graphic[0].dx;
+  section[0].dy = dy / graphic[0].dy;
+
+  // if (section[0].x != x)   MoveSection = TRUE;
+  // if (section[0].y != y)   MoveSection = TRUE;
+  // if (section[0].dx != dx) MoveSection = TRUE;
+  // if (section[0].dy != dy) MoveSection = TRUE;
+
+  SetSectionSizes (section);
+  Refresh ();
+
+  return (TRUE);
+}
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/DrawFrame.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/DrawFrame.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/DrawFrame.c	(revision 30118)
@@ -5,6 +5,6 @@
 int DrawFrame (KapaGraphWidget *graph) {
   
-  int i, j, Nticks, P;
-  double fx, fy, dfx, dfy, lweight;
+  int i, j, Nticks, P, doffset;
+  double fx, fy, dfx, dfy, dx = 0, dy = 0, lweight;
   Graphic *graphic;
   TickMarkData *ticks;
@@ -15,12 +15,21 @@
   /* each axis is drawn independently, but ticks and labels are placed according to perpendicular distance. */
   for (i = 0; i < 4; i++) {
-    fx  = graph[0].axis[i].fx;
-    fy  = graph[0].axis[i].fy;
-    dfx = graph[0].axis[i].dfx;
-    dfy = graph[0].axis[i].dfy;
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-
     lweight = MAX (0, MIN (10, graph[0].axis[i].lweight));
     color = MAX (0, MIN (15, graph[0].axis[i].color));
+
+    /* temporarily assume rectilinear axes */
+    doffset = ((int)(lweight) % 2) ? 0.5*(lweight - 1) : 0.5*lweight;
+    if (i == 0) { dx = doffset; dy = 0.0; }
+    if (i == 2) { dx = doffset; dy = 0.0; }
+    if (i == 1) { dx = 0.0; dy = doffset; }
+    if (i == 3) { dx = 0.0; dy = doffset; }
+
+    fx  = graph[0].axis[i].fx - dx;
+    fy  = graph[0].axis[i].fy - dy;
+    dfx = graph[0].axis[i].dfx + 2*dx;
+    dfy = graph[0].axis[i].dfy + 2*dy;
+
+    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    P *= (1 + 0.25*lweight);
 
     XSetLineAttributes (graphic->display, graphic->gc, lweight, LineSolid, CapNotLast, JoinMiter);
@@ -43,5 +52,5 @@
 }
 
-int PrintTick (char *string, double value, double min, double max) {
+int PrintTick (char *string, double value, double min, double max, int nsignif) {
 
   int Nexp = 0;
@@ -54,16 +63,23 @@
   }
 
-  double lvalue = log10(fabs(value));
-
-  if (isfinite(lvalue)) {
-    Nexp = fabs(lvalue);
-  } else {
-    Nexp = 0;
-  }
-  
+//   double lvalue = log10(fabs(value));
+//   if (isfinite(lvalue)) {
+//     Nexp = fabs(lvalue);
+//   } else {
+//     Nexp = 0;
+//   }
+  
+  Nexp = abs(nsignif);
+
   if (Nexp > 3) {
     Nchar = sprintf (string, "%.1e", value);
   } else {
-    Nchar = sprintf (string, "%.1f", value);
+    if (nsignif < 0) {
+      char format[16];
+      snprintf (format, 16, "%%.%df", -1 * nsignif);
+      Nchar = sprintf (string, format, value);
+    } else {
+      Nchar = sprintf (string, "%.1f", value);
+    }
   }
   return Nchar;
@@ -129,5 +145,5 @@
     yt = fy + (value-min)*dfy/(max - min) + dy;
 
-    PrintTick (string, value, min, max);
+    PrintTick (string, value, min, max, tick->nsignif);
     DrawRotText (xt, yt, string, pos, 0.0);
   }
@@ -136,5 +152,5 @@
 # define MIN_RANGE 1e-10
 
-void AxisTickScale (Axis *axis, double *major, double *minor) {
+void AxisTickScale (Axis *axis, double *major, double *minor, int *nsignif) {
 
   double range, lrange, factor, mantis, fmantis, power;
@@ -152,4 +168,6 @@
   }
   
+  // how many significant digits are needed?
+
   power = MAX(pow(10.0, factor), MIN_RANGE);
   fmantis = pow(10.0, mantis);
@@ -160,7 +178,9 @@
     *major = 0.5 * power;
     *minor = 0.1 * power;
+    *nsignif = factor - 1;
     if (axis[0].areticks == 1) {
       *major = 0.25 * power;
       *minor = 0.05 * power;
+      *nsignif = factor - 2;
     }	  
   }
@@ -168,7 +188,9 @@
     *major = 1.0 * power;
     *minor = 0.2 * power;
+    *nsignif = factor;
     if (axis[0].areticks == 1) {
       *major = 0.5 * power;
       *minor = 0.1 * power;
+      *nsignif = factor - 1;
     }	  
   }
@@ -176,7 +198,9 @@
     *major = 1.0 * power;
     *minor = 0.5 * power;
+    *nsignif = factor;
     if (axis[0].areticks == 1) {
       *major = 1.0 * power;
       *minor = 0.2 * power;
+      *nsignif = factor;
     }	  
   }
@@ -184,7 +208,9 @@
     *major = 2.0 * power;
     *minor = 0.5 * power;
+    *nsignif = factor;
     if (axis[0].areticks == 1) {
       *major = 1.0 * power;
       *minor = 0.5 * power;
+      *nsignif = factor;
     }	  
   }
@@ -192,7 +218,9 @@
     *major = 2.5 * power;
     *minor = 0.5 * power;
+      *nsignif = factor - 1;
     if (axis[0].areticks == 1) {
       *major = 2.0 * power;
       *minor = 0.5 * power;
+      *nsignif = factor;
     }	  
   }
@@ -203,5 +231,5 @@
   TickMarkData *ticks;
   double range, major, minor, first, value, dPixels, overshoot;
-  int i, NTICKS, nPixels, done, ifirst;
+  int i, NTICKS, nPixels, done, ifirst, nsignif;
 
   *nticks = 0;
@@ -223,5 +251,5 @@
   dPixels = nPixels / range; // axis pixel-scale
 
-  AxisTickScale (axis, &major, &minor);
+  AxisTickScale (axis, &major, &minor, &nsignif);
 
   // be a little generous 
@@ -256,4 +284,5 @@
     ticks[i].IsLabel = (ticks[i].IsMajor && axis->islabel);
     ticks[i].value = value;
+    ticks[i].nsignif = nsignif;
     if (range > 0) 
       value += minor;
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/Image.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/Image.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/Image.c	(revision 30118)
@@ -88,5 +88,8 @@
 
   InitButtonSize (&image[0].PS_button, PS_width, PS_height, PS_bits);
-  InitButtonFunc (&image[0].PS_button, PSfunction);
+  // InitButtonFunc (&image[0].PS_button, PSfunction);
+  image->PS_button.function_1 = PSfunction;
+  image->PS_button.function_2 = PNGfunction;
+  image->PS_button.function_3 = JPEGfunction;
 
   InitButtonSize (&image[0].grey_button, grey_width, grey_height, grey_bits);
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/JPEGit24.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/JPEGit24.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/JPEGit24.c	(revision 30118)
@@ -8,6 +8,16 @@
 # define WHITE_B 255
 
+int JPEGcommand (int sock) {
+
+  int status;
+  char filename[1024];
+
+  KiiScanMessage (sock, "%s", filename);
+  status = JPEGit24 (filename);
+  return (status);
+}
+
 // XXX this currently writes out the jpeg for just the active image
-int JPEGit24 (int sock) {
+int JPEGit24 (char *filename) {
 
   struct jpeg_compress_struct cinfo;
@@ -31,9 +41,5 @@
   unsigned short *in_pix, *in_pix_ref;
   unsigned char *pixel1, *pixel2, *pixel3;
-  char filename[1024];
   FILE *f;
-
-  /* expect a line telling the number of bytes and a filename */
-  KiiScanMessage (sock, "%s", filename);
 
   graphic = GetGraphic();
@@ -196,8 +202,7 @@
     palette = KapaPNGPalette (&Npalette);
 
-    buffer = bDrawBufferCreate (dx, dy);
-    bDrawSetBuffer (buffer);
+    buffer = bDrawBufferCreate (dx, dy, 1, palette, Npalette);
     for (i = 0; i < NOVERLAYS; i++) {
-      if (image[i].overlay[i].active) bDrawOverlay (image, i);
+      if (image[0].overlay[i].active) bDrawOverlay (buffer, image, i);
     }
 
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/PNGit.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/PNGit.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/PNGit.c	(revision 30118)
@@ -7,22 +7,26 @@
 */
 
-bDrawBuffer *bDrawBufferCreate8bitRGB (int Nx, int Ny);
-int bDrawImage (bDrawBuffer *buffer, Graphic *graphic);
+int PNGcommand (int sock) {
 
-int PNGit (int sock) {
+  int status;
+  char filename[1024];
+
+  KiiScanMessage (sock, "%s", filename);
+  status = PNGit (filename);
+  return (status);
+}
+
+int PNGit (char *filename) {
 
   FILE *f;
   png_structp png_ptr;
   png_infop info_ptr;
-  int status, Npalette;
-  char filename[1024];
+  int i, status, Npalette, Nsection;
   bDrawBuffer *buffer = NULL;
   Graphic *graphic = NULL;
   png_color *palette = NULL;
+  Section *section;
 
   graphic = GetGraphic();
-
-  /* expect a line telling the number of bytes and a filename */
-  KiiScanMessage (sock, "%s", filename);
 
   f = fopen (filename, "w");
@@ -62,14 +66,22 @@
   png_init_io (png_ptr, f);
 
+  palette = KapaPNGPalette (&Npalette);
+
+  // do we have an image in any of the sections?
+  Nsection = GetNumberOfSections ();
+  int haveImage = FALSE;
+  for (i = 0; !haveImage && (i < Nsection); i++) {
+    section = GetSectionByNumber (i);
+    haveImage = (section->image != NULL);
+  }
+
   /* see docs for write-row-callback to provide progress info */
-# define PALETTE 1
-  if (PALETTE) {
-    png_set_IHDR (png_ptr, info_ptr, graphic->dx, graphic->dy, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 
-    palette = KapaPNGPalette (&Npalette);
-    png_set_PLTE (png_ptr, info_ptr, palette, Npalette); 
-  } else {
+  if (haveImage) {
     // png_set_IHDR (png_ptr, info_ptr, graphic->dx, graphic->dy, 16, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
     png_set_IHDR (png_ptr, info_ptr, graphic->dx, graphic->dy, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
     png_set_sRGB (png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
+  } else {
+    png_set_IHDR (png_ptr, info_ptr, graphic->dx, graphic->dy, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 
+    png_set_PLTE (png_ptr, info_ptr, palette, Npalette); 
   }
 
@@ -81,9 +93,9 @@
   png_write_info (png_ptr, info_ptr);
 
-  if (PALETTE) {
-    buffer = bDrawIt ();
+  if (haveImage) {
+    buffer = bDrawIt (palette, Npalette, 3);
+    // bDrawImage (buffer, graphic);
   } else {
-    buffer = bDrawBufferCreate8bitRGB(graphic->dx, graphic->dy);
-    bDrawImage (buffer, graphic);
+    buffer = bDrawIt (palette, Npalette, 1);
   }
 
@@ -93,215 +105,6 @@
   
   bDrawBufferFree (buffer);
-  free (palette);
   fclose (f);
   return (TRUE);
 
 }
-
-/* For color images, I need to define the relationship between the drawing colors and the RGB values? */
-
-
-bDrawBuffer *bDrawBufferCreate8bitRGB (int Nx, int Ny) {
-
-  int i, j;
-  bDrawBuffer *buffer;
-
-  ALLOCATE (buffer, bDrawBuffer, 1);
-  buffer[0].Nx = Nx;
-  buffer[0].Ny = Ny;
-
-  ALLOCATE (buffer[0].pixels, bDrawColor *, Ny);
-  for (i = 0; i < Ny; i++) {
-    ALLOCATE (buffer[0].pixels[i], bDrawColor, 3*Nx);
-    for (j = 0; j < 3*Nx; j+=3) {
-      buffer[0].pixels[i][j+0] = 0xff;
-      buffer[0].pixels[i][j+1] = 0xff;
-      buffer[0].pixels[i][j+2] = 0xff;
-    }
-  }
-  return (buffer);
-}
-
-# define WHITE_R 255
-# define WHITE_G 255
-# define WHITE_B 255
-# define MY_SWAP_INT(A,B) { int tmp; tmp = A; A = B; B = tmp; }
-
-int bDrawImage (bDrawBuffer *buffer, Graphic *graphic) {
-  
-  Section *section;
-  KapaImageWidget *image;
-
-  int ii, i, j;
-  int i_start, i_end, j_start, j_end;
-  int I_start, J_start;
-  int dropback;  /* this is a bit of a kludge... */
-  int dx, dy, DX, DY, inDX, inDY;
-  int expand_in, expand_out;
-  double expand, Ix, Iy;
-  unsigned char *out_pix;
-  unsigned short *in_pix, *in_pix_ref;
-  unsigned char *pixel1, *pixel2, *pixel3;
-
-  bDrawColor *line_buffer;
-
-  section = GetActiveSection();
-  image   = section->image;
-  if (image == NULL) return (TRUE);
-
-  ALLOCATE (pixel1, unsigned char, graphic[0].Npixels);
-  ALLOCATE (pixel2, unsigned char, graphic[0].Npixels);
-  ALLOCATE (pixel3, unsigned char, graphic[0].Npixels);
-
-  /** cmap[i].pixel must be defined even if X is not used **/
-  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
-    pixel1[i] = graphic[0].cmap[i].red >> 8;
-    pixel2[i] = graphic[0].cmap[i].green >> 8;
-    pixel3[i] = graphic[0].cmap[i].blue >> 8;
-  }
-
-  assert ((image[0].picture.expand >= 1) || (image[0].picture.expand <= -2));
-  expand = expand_in = expand_out = 1.0;
-  if (image[0].picture.expand > 0) {
-    expand = 1 / (1.0*image[0].picture.expand);
-    expand_out = image[0].picture.expand;
-    expand_in  = 1;
-  }
-  if (image[0].picture.expand < 0) {
-    expand = fabs((double)image[0].picture.expand);
-    expand_out = 1;
-    expand_in  = -image[0].picture.expand;
-  }
-
-  dx = image[0].picture.dx;
-  dy = image[0].picture.dy;
-  DX = image[0].image[0].matrix.Naxis[0];
-  DY = image[0].image[0].matrix.Naxis[1];
-
-  // i_start, j_start are the closest lit screen pixel to 0,0
-  // I_start, J_start are the image pixel corresponding to i_start, j_start
-  Picture_Lower (&i_start, &j_start, &I_start, &J_start, &image[0].image[0].matrix, &image[0].picture);
-
-  // i_end, j_end are the closest lit screen pixel to dx, dy
-  // I_end, J_end are the image pixel corresponding to i_end, j_end
-  Picture_Upper (&i_end, &j_end, i_start, j_start, &image[0].image[0].matrix, &image[0].picture);
-
-  assert (i_start <= i_end);
-  assert (j_start <= j_end);
-
-  Ix = image[0].picture.flipx ? I_start - 1 : I_start;
-  Iy = image[0].picture.flipy ? J_start - 1 : J_start;
-
-  inDX = image[0].picture.flipx ? -1 : +1;
-  inDY = image[0].picture.flipy ? -1 : +1;
-
-  dropback = expand_out - (i_end - i_start) % expand_out;
-  if ((i_end - i_start) % expand_out == 0) dropback = 0;
-
-  ALLOCATE (line_buffer, bDrawColor, 3*dx);
-
-  in_pix_ref  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
-
-  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
-
-  /**** fill in bottom area ****/
-  out_pix = line_buffer;
-  for (i = 0; i < dx; i++, out_pix+=3) {
-    out_pix[0] = WHITE_R;
-    out_pix[1] = WHITE_G;
-    out_pix[2] = WHITE_B;
-  }
-  for (j = 0; j < j_start; j++) {
-    memcpy (buffer[0].pixels[j], line_buffer, 3*dx);
-  }
-  
-  /*** fill in the image data region ***/
-  for (j = j_start; j < j_end; j+= expand_out, in_pix_ref += inDY*expand_in*DX) {
-    
-    /* create one output image line */
-    in_pix = in_pix_ref;
-    out_pix = line_buffer;
-
-    /**** fill in area to the left of the picture ****/
-    for (i = 0; i < i_start; i++, out_pix+=3) {
-      out_pix[0] = WHITE_R;
-      out_pix[1] = WHITE_G;
-      out_pix[2] = WHITE_B;
-    }
-    
-    /*** fill in the picture region ***/
-    for (i = i_start; i < i_end; i+=expand_out, in_pix += inDX*expand_in) {
-      for (ii = 0; ii < expand_out; ii++, out_pix+=3) {
-	out_pix[0] = pixel1[*in_pix];
-	out_pix[1] = pixel2[*in_pix];
-	out_pix[2] = pixel3[*in_pix];
-      }
-    }
-    
-    /**** fill in area to the right of the picture ****/
-    for (i = i_end; i < dx; i++, out_pix+=3) {
-      out_pix[0] = WHITE_R;
-      out_pix[1] = WHITE_G;
-      out_pix[2] = WHITE_B;
-    }
-
-    /* write out the image line expand_out times */
-    for (i = 0; i < expand_out; i++) {
-      memcpy (buffer[0].pixels[j + i], line_buffer, 3*dx);
-    }
-  }
-
-  /**** fill in top area ****/
-  out_pix = line_buffer;
-  for (i = 0; i < dx; i++, out_pix+=3) { 
-    out_pix[0] = WHITE_R;
-    out_pix[1] = WHITE_G;
-    out_pix[2] = WHITE_B;
-  }
-  for (j = j_end; j < dy; j++) {
-    memcpy (buffer[0].pixels[j], line_buffer, 3*dx);
-  }
-
-  free (pixel1);
-  free (pixel2);
-  free (pixel3);
-  free (line_buffer);
-
-  return (TRUE);
-}
-
-# if (0)
-
-  /* I need to write the overlay objects on the jpeg image.
-     if i can write / overwrite data in jpeg buffer, then do it here,
-     otherwise i need to create a temporary image buffer, then write the 
-     scanlines to that buffer */
-
-  {
-    int Npalette;
-    png_color *palette;
-    bDrawColor white, color;
-    bDrawBuffer *buffer;
-
-    palette = KapaPNGPalette (&Npalette);
-
-    buffer = bDrawBufferCreate (dx, dy);
-    bDrawSetBuffer (buffer);
-    for (i = 0; i < NOVERLAYS; i++) {
-      if (image[i].overlay[i].active) bDrawOverlay (image, i);
-    }
-
-    white = KapaColorByName ("white");
-    for (j = 0; j < dy; j++) {
-      for (i = 0; i < dx; i++) {
-	color = buffer[0].pixels[j][i];
-	if (color == white) continue;
-	image_buffer[j*3*dx + 3*i + 0] = palette[color].red;
-	image_buffer[j*3*dx + 3*i + 1] = palette[color].green;
-	image_buffer[j*3*dx + 3*i + 2] = palette[color].blue;
-      }
-    }
-    bDrawBufferFree (buffer);
-  }
-
-# endif
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/PPMit.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/PPMit.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/PPMit.c	(revision 30118)
@@ -30,5 +30,5 @@
   fprintf (f, "255\n");
 
-  buffer = bDrawIt ();
+  buffer = bDrawIt (palette, Npalette, 1);
 
   ALLOCATE (line, char, 3*dx);
@@ -47,4 +47,3 @@
   bDrawBufferFree (buffer);
   return (TRUE);
-
 }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSFrame.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSFrame.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSFrame.c	(revision 30118)
@@ -4,6 +4,6 @@
 int PSFrame (KapaGraphWidget *graph, FILE *f) {
   
-  int i, j, Nticks, P;
-  double fx, fy, dfx, dfy, lweight;
+  int i, j, Nticks, P, doffset;
+  double fx, fy, dfx, dfy, dx = 0, dy = 0, lweight;
   Graphic *graphic;
   TickMarkData *ticks;
@@ -15,12 +15,21 @@
   fprintf (f, "1 setlinewidth\n");
   for (i = 0; i < 4; i++) {
-    fx  = graph[0].axis[i].fx;
-    fy  = graphic->dy - graph[0].axis[i].fy;
-    dfx = graph[0].axis[i].dfx;
-    dfy = -graph[0].axis[i].dfy;
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-
     lweight = MAX (0, MIN (10, graph[0].axis[i].lweight));
     color = MAX (0, MIN (15, graph[0].axis[i].color));
+
+    /* temporarily assume rectilinear axes */
+    doffset = ((int)(lweight) % 2) ? 0.5*(lweight - 1) : 0.5*lweight;
+    if (i == 0) { dx = doffset; dy = 0.0; }
+    if (i == 2) { dx = doffset; dy = 0.0; }
+    if (i == 1) { dx = 0.0; dy = doffset; }
+    if (i == 3) { dx = 0.0; dy = doffset; }
+
+    fx  = graph[0].axis[i].fx - dx;
+    fy  = graphic->dy - graph[0].axis[i].fy - dy;
+    dfx = graph[0].axis[i].dfx + 2*dx;
+    dfy = -graph[0].axis[i].dfy + 2*dy;
+
+    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    P *= (1 + 0.25*lweight);
 
     fprintf (f, "%.1f setlinewidth\n", lweight);
@@ -95,5 +104,5 @@
     yt = fy + (value-min)*dfy/(max - min) + dy;
 
-    PrintTick (string, value, min, max);
+    PrintTick (string, value, min, max, tick->nsignif);
     PSRotText (f, xt, yt, string, pos, 0.0);
   }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSimage.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSimage.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSimage.c	(revision 30118)
@@ -13,7 +13,11 @@
   graphic = GetGraphic();
 
-  fprintf (f, " newpath 0 0 moveto %d 0 lineto %d %d lineto 0 %d lineto closepath clip\n\n", 
-	   image[0].picture.dx, image[0].picture.dx, image[0].picture.dy, image[0].picture.dy);
+  fprintf (f, " newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath\n\n", 
+	   (int) image[0].picture.x,                       graphic->dy - (int) image[0].picture.y, 
+	   (int) image[0].picture.x + image[0].picture.dx, graphic->dy - (int) image[0].picture.y, 
+	   (int) image[0].picture.x + image[0].picture.dx, graphic->dy - (int) image[0].picture.y - image[0].picture.dy, 
+	   (int) image[0].picture.x,                       graphic->dy - (int) image[0].picture.y - image[0].picture.dy); 
   fprintf (f, "gsave %% encloses image\n");
+  fprintf (f, "%d %d translate\n", (int) image[0].picture.x, graphic->dy - (int) image[0].picture.y - image[0].picture.dy);
   fprintf (f, "%d %d 8\n", image[0].picture.dx, image[0].picture.dy);
   fprintf (f, "[1 0 0 1 0 0]\n");
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSit.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSit.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/PSit.c	(revision 30118)
@@ -87,4 +87,7 @@
   for (i = 0; i < Nsection; i++) {
     section = GetSectionByNumber (i);
+    if (section->image) {
+      PSimage (section->image, f);
+    }
     if (section->graph) {
       PSFrame (section->graph, f); 
@@ -92,7 +95,4 @@
       PSLabels (section->graph, f);
       PSTextlines (section->graph, f);
-    }
-    if (section->image) {
-      PSimage (section->image, f);
     }
   }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/Resize.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/Resize.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/Resize.c	(revision 30118)
@@ -39,2 +39,66 @@
   return (TRUE);
 }
+
+// resise the window so the image in the currently active window fills its section
+int ResizeByImage (int sock) {
+ 
+  int i, Nsection;
+  unsigned int NX, NY;
+  double dx, dy;
+  int dXm, dXp, dYm, dYp;
+  double x0, y0, x1, y1, expand;
+  Section *section;
+  Graphic *graphic;
+  KapaImageWidget *image;
+
+  graphic = GetGraphic();
+
+  section = GetActiveSection();
+
+  image = section->image;
+  if (!image) {
+    fprintf (stderr, "no image to define size\n");
+    return (TRUE);
+  }
+
+  GetGraphBoundary (section, &x0, &y0, &x1, &y1, &dXm, &dXp, &dYm, &dYp);
+
+  expand = 1.0;
+  if (image[0].picture.expand > 0) {
+    expand = image[0].picture.expand;
+  }
+  if (image[0].picture.expand < 0) {
+    expand = 1.0 / fabs((double)image[0].picture.expand);
+  }
+
+  // pixel dimensions of the imaging region + boundary
+  dx = image[0].image[0].matrix.Naxis[0]*expand + x1;
+  dy = image[0].image[0].matrix.Naxis[1]*expand + y1;
+
+  NX = dx / section[0].dx;
+  NY = dy / section[0].dy;
+
+  NX = MAX(NX, MIN_WIDTH); 
+  NY = MAX(NY, MIN_HEIGHT); 
+
+  // if the new size is the same as the old size, do nothing.
+  if ((graphic->dx == NX) && (graphic->dy == NY)) return (TRUE);
+
+  // set the new window size
+  graphic->dx = NX; 
+  graphic->dy = NY; 
+
+  if (USE_XWINDOW) XResizeWindow (graphic->display, graphic->window, NX, NY);
+
+  // reset the sizes for all sections
+  Nsection = GetNumberOfSections ();
+  for (i = 0; i < Nsection; i++) {
+      section = GetSectionByNumber (i);
+      SetSectionSizes (section);
+  }
+
+  if (USE_XWINDOW) XClearWindow (graphic->display, graphic->window);
+  Refresh ();
+
+  return (TRUE);
+}
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/SetGraphSize.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/SetGraphSize.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/SetGraphSize.c	(revision 30118)
@@ -5,13 +5,76 @@
 
 void SetGraphSize (Section *section) {
+
+  int dXm, dXp, dYm, dYp;
+  double x0, y0, x1, y1;
+  KapaGraphWidget *graph;
+  Graphic *graphic;
+
+  GetGraphBoundary(section, &x0, &y0, &x1, &y1, &dXm, &dXp, &dYm, &dYp);
+
+  if (section == NULL) return;
+  graph = section->graph;
+  if (graph == NULL) return;
+
+  graphic = GetGraphic ();
+
+  double X0 = graphic[0].dx * section[0].x  + x0;
+  double Y0 = graphic[0].dy * section[0].y  + y0;
+  double dX = graphic[0].dx * section[0].dx - x1;
+  double dY = graphic[0].dy * section[0].dy - y1;
+
+  /* define locations of coordinate axes */
+  graph[0].axis[0].fx  = X0;
+  graph[0].axis[0].fy  = graphic->dy - Y0;
+  graph[0].axis[0].dfx = dX;
+  graph[0].axis[0].dfy = 0;
+
+  graph[0].axis[1].fx  = X0;
+  graph[0].axis[1].fy  = graphic->dy - Y0;
+  graph[0].axis[1].dfx = 0;
+  graph[0].axis[1].dfy = -dY;
+
+  graph[0].axis[2].fx  = X0;
+  graph[0].axis[2].fy  = graphic->dy - Y0 - dY;
+  graph[0].axis[2].dfx = dX;
+  graph[0].axis[2].dfy = 0;
+
+  graph[0].axis[3].fx  = X0 + dX;
+  graph[0].axis[3].fy  = graphic->dy - Y0;
+  graph[0].axis[3].dfx = 0;
+  graph[0].axis[3].dfy = -dY;
+
+  /* define locations of axis labels */
+  graph[0].label[LABELLL].x = graph[0].axis[0].fx;
+  graph[0].label[LABELLL].y = graph[0].axis[0].fy + dXm;
+  graph[0].label[LABELX0].x = graph[0].axis[0].fx + 0.5*graph[0].axis[0].dfx;
+  graph[0].label[LABELX0].y = graph[0].axis[0].fy + dXm;
+  graph[0].label[LABELLR].x = graph[0].axis[0].fx + graph[0].axis[0].dfx;
+  graph[0].label[LABELLR].y = graph[0].axis[0].fy + dXm;
+
+  graph[0].label[LABELUL].x = graph[0].axis[2].fx;
+  graph[0].label[LABELUL].y = graph[0].axis[2].fy - dXp;
+  graph[0].label[LABELX1].x = graph[0].axis[2].fx + 0.5*graph[0].axis[2].dfx;
+  graph[0].label[LABELX1].y = graph[0].axis[2].fy - dXp;
+  graph[0].label[LABELUR].x = graph[0].axis[2].fx + graph[0].axis[2].dfx;
+  graph[0].label[LABELUR].y = graph[0].axis[2].fy - dXp;
+
+  graph[0].label[LABELY0].y = graph[0].axis[1].fy + 0.5*graph[0].axis[1].dfy;
+  graph[0].label[LABELY0].x = graph[0].axis[1].fx - dYm;
+
+  graph[0].label[LABELY1].y = graph[0].axis[3].fy + 0.5*graph[0].axis[3].dfy;
+  graph[0].label[LABELY1].x = graph[0].axis[3].fx + dYp;
+
+  return;
+}
+
+int GetGraphBoundary (Section *section, double *x0, double *y0, double *x1, double *y1, int *dXm, int *dXp, int *dYm, int *dYp) {
 
   int i, Nticks;
   int fontsize, Nc = 0;
   int textpad, textdY, WdY;
-  int dXm, dXp, dYm, dYp;
   double padXm, padXp, padYm, padYp;
   double minPADx, maxPADx, minPADy;
   double minPAD, maxPAD;
-  double X0, Y0, dX, dY;
   char string[64], *fontname;
   KapaGraphWidget *graph;
@@ -19,7 +82,17 @@
   TickMarkData *ticks;
 
-  if (section == NULL) return;
+  *x0 = 0.0;
+  *y0 = 0.0;
+  *x1 = 0.0;
+  *y1 = 0.0;
+
+  *dXm = 0;
+  *dXp = 0;
+  *dYm = 0;
+  *dYp = 0;
+
+  if (section == NULL) return FALSE;
   graph = section->graph;
-  if (graph == NULL) return;
+  if (graph == NULL) return FALSE;
 
   graphic = GetGraphic ();
@@ -40,7 +113,7 @@
   // these depend on (a) existence of tick labels and (b) auto-offset or not
   if (isnan(graph[0].axis[0].labelPad)) {
-    dXm = (graph[0].axis[0].islabel) ? maxPAD  : minPAD;
-  } else {
-    dXm = graph[0].axis[0].labelPad * fontsize;
+    *dXm = (graph[0].axis[0].islabel) ? maxPAD  : minPAD;
+  } else {
+    *dXm = graph[0].axis[0].labelPad * fontsize;
   }
   if (isnan(graph[0].axis[0].pad)) {
@@ -53,7 +126,7 @@
   // these depend on (a) existence of tick labels and (b) auto-offset or not
   if (isnan(graph[0].axis[2].labelPad)) {
-    dXp = (graph[0].axis[2].islabel) ? maxPAD : minPAD;
-  } else {
-    dXp = graph[0].axis[2].labelPad * fontsize;
+    *dXp = (graph[0].axis[2].islabel) ? maxPAD : minPAD;
+  } else {
+    *dXp = graph[0].axis[2].labelPad * fontsize;
   }
   if (isnan(graph[0].axis[2].pad)) {
@@ -73,5 +146,5 @@
       if (!ticks[i].IsMajor) continue;
 
-      int Nchar = PrintTick (string, ticks[i].value, graph[0].axis[1].min, graph[0].axis[1].max);
+      int Nchar = PrintTick (string, ticks[i].value, graph[0].axis[1].min, graph[0].axis[1].max, ticks[i].nsignif);
 
       Nc = MAX (Nc, Nchar);
@@ -80,7 +153,7 @@
   }
   if (isnan(graph[0].axis[1].labelPad)) {
-    dYm = (graph[0].axis[1].islabel) ? (0.7*(Nc + 1.5)*fontsize) : minPAD;
-  } else {
-    dYm = graph[0].axis[1].labelPad * fontsize;
+    *dYm = (graph[0].axis[1].islabel) ? (0.7*(Nc + 1.5)*fontsize) : minPAD;
+  } else {
+    *dYm = graph[0].axis[1].labelPad * fontsize;
   }
   if (isnan(graph[0].axis[1].pad)) {
@@ -98,5 +171,5 @@
     for (i = 0; i < Nticks; i++) {
       if (!ticks[i].IsMajor) continue;
-      int Nchar = PrintTick (string, ticks[i].value, graph[0].axis[3].min, graph[0].axis[3].max);
+      int Nchar = PrintTick (string, ticks[i].value, graph[0].axis[3].min, graph[0].axis[3].max, ticks[i].nsignif);
       Nc = MAX (Nc, Nchar);
     }
@@ -104,7 +177,7 @@
   }
   if (isnan(graph[0].axis[3].labelPad)) {
-    dYp = (graph[0].axis[3].islabel) ? (0.7*(Nc + 1.5)*fontsize) : minPAD;
-  } else {
-    dYp = graph[0].axis[3].labelPad * fontsize;
+    *dYp = (graph[0].axis[3].islabel) ? (0.7*(Nc + 1.5)*fontsize) : minPAD;
+  } else {
+    *dYp = graph[0].axis[3].labelPad * fontsize;
   }
   if (isnan(graph[0].axis[3].pad)) {
@@ -115,8 +188,8 @@
 
   /* basic size of the graph in Xwindow coordinates, but measured from lower-left corner */
-  X0 = graphic[0].dx * section[0].x + padYm;
-  Y0 = graphic[0].dy * section[0].y + padXm;
-  dX = graphic[0].dx * section[0].dx - padYm - padYp;
-  dY = graphic[0].dy * section[0].dy - padXm - padXp;
+  *x0 = padYm;
+  *y0 = padXm;
+  *x1 = padYm + padYp;
+  *y1 = padXm + padXp;
 
   // if we are tied to an image, make mods as needed
@@ -128,70 +201,24 @@
     switch (section->image->location) {
       case 0:
-	// no changes?
 	break;
       case 1:
-        Y0 = graphic[0].dy * section[0].y  + padXm         + 2*PAD1 + WdY + 2;
-        dY = graphic[0].dy * section[0].dy - padXm - padXp - 4*PAD1 - 1 - WdY - COLORPAD;
+        *y0 = padXm + 2*PAD1 + WdY + 2;
+        *y1 = padXm + padXp + 4*PAD1 + 1 + WdY + COLORPAD;
         break;
       case 3:
-        dY = graphic[0].dy * section[0].dy - padXm - padXp - 4*PAD1 - 1 - WdY - COLORPAD;
+        *y1 = padXm + padXp + 4*PAD1 + 1 + WdY + COLORPAD;
         break;
       case 2:
-        X0 = graphic[0].dx * section[0].x  + padYm         + 2*PAD1 + ZOOM_X;
-        dX = graphic[0].dx * section[0].dx - padYm - padYp - 3*PAD1 - ZOOM_X;
-	dY = graphic[0].dy * section[0].dy - padXm - padXp - 2*PAD1 - COLORPAD;
+        *x0 = padYm + 2*PAD1 + ZOOM_X;
+        *x1 = padYm + padYp + 3*PAD1 + ZOOM_X;
+	*y1 = padXm + padXp + 2*PAD1 + COLORPAD;
         break;
       case 4:
-        dX = graphic[0].dx * section[0].dx - padYm - padYp - 3*PAD1 - ZOOM_X;
-	dY = graphic[0].dy * section[0].dy - padXm - padXp - 2*PAD1 - COLORPAD;
+        *x1 = padYm + padYp + 3*PAD1 + ZOOM_X;
+	*y1 = padXm + padXp + 2*PAD1 + COLORPAD;
         break;
     }
   }
 
-  /* define locations of coordinate axes */
-  graph[0].axis[0].fx  = X0;
-  graph[0].axis[0].fy  = graphic->dy - Y0;
-  graph[0].axis[0].dfx = dX;
-  graph[0].axis[0].dfy = 0;
-
-  graph[0].axis[1].fx  = X0;
-  graph[0].axis[1].fy  = graphic->dy - Y0;
-  graph[0].axis[1].dfx = 0;
-  graph[0].axis[1].dfy = -dY;
-
-  graph[0].axis[2].fx  = X0;
-  graph[0].axis[2].fy  = graphic->dy - Y0 - dY;
-  graph[0].axis[2].dfx = dX;
-  graph[0].axis[2].dfy = 0;
-
-  graph[0].axis[3].fx  = X0 + dX;
-  graph[0].axis[3].fy  = graphic->dy - Y0;
-  graph[0].axis[3].dfx = 0;
-  graph[0].axis[3].dfy = -dY;
-
-  /* define locations of axis labels */
-  graph[0].label[LABELLL].x = graph[0].axis[0].fx;
-  graph[0].label[LABELLL].y = graph[0].axis[0].fy + dXm;
-  graph[0].label[LABELX0].x = graph[0].axis[0].fx + 0.5*graph[0].axis[0].dfx;
-  graph[0].label[LABELX0].y = graph[0].axis[0].fy + dXm;
-  graph[0].label[LABELLR].x = graph[0].axis[0].fx + graph[0].axis[0].dfx;
-  graph[0].label[LABELLR].y = graph[0].axis[0].fy + dXm;
-
-  graph[0].label[LABELUL].x = graph[0].axis[2].fx;
-  graph[0].label[LABELUL].y = graph[0].axis[2].fy - dXp;
-  graph[0].label[LABELX1].x = graph[0].axis[2].fx + 0.5*graph[0].axis[2].dfx;
-  graph[0].label[LABELX1].y = graph[0].axis[2].fy - dXp;
-  graph[0].label[LABELUR].x = graph[0].axis[2].fx + graph[0].axis[2].dfx;
-  graph[0].label[LABELUR].y = graph[0].axis[2].fy - dXp;
-
-  graph[0].label[LABELY0].y = graph[0].axis[1].fy + 0.5*graph[0].axis[1].dfy;
-  graph[0].label[LABELY0].x = graph[0].axis[1].fx - dYm;
-
-  graph[0].label[LABELY1].y = graph[0].axis[3].fy + 0.5*graph[0].axis[3].dfy;
-  graph[0].label[LABELY1].x = graph[0].axis[3].fx + dYp;
-
-  // fprintf (stderr, "section %s, %f,%f : %f,%f\n", section->name, X0, Y0, dX, dY);
-
-  /* these are wrong and have to be adjusted to sit in the corners */
-
+  return (TRUE);
 }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawFrame.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawFrame.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawFrame.c	(revision 30118)
@@ -2,8 +2,8 @@
 // bDrawLine is a function, not a macro like DrawLine
 
-int bDrawFrame (KapaGraphWidget *graph) {
+int bDrawFrame (bDrawBuffer *buffer, KapaGraphWidget *graph) {
   
-  int i, j, Nticks, P;
-  double fx, fy, dfx, dfy, lweight;
+  int i, j, Nticks, P, doffset;
+  double fx, fy, dfx, dfy, lweight, dx = 0, dy = 0;
   // Graphic graphic; is not needed
   TickMarkData *ticks;
@@ -14,19 +14,27 @@
   /* each axis is drawn independently */
   for (i = 0; i < 4; i++) {
-    fx  = graph[0].axis[i].fx;
-    fy  = graph[0].axis[i].fy;
-    dfx = graph[0].axis[i].dfx;
-    dfy = graph[0].axis[i].dfy;
-    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
-
     lweight = MAX (0, MIN (10, graph[0].axis[i].lweight));
     color = MAX (0, MIN (15, graph[0].axis[i].color));
 
-    bDrawSetStyle (color, lweight, 0);
-    // function about sets solor and weight
+    /* temporarily assume rectilinear axes */
+    doffset = ((int)(lweight) % 2) ? 0.5*(lweight - 1) : 0.5*lweight;
+    if (i == 0) { dx = doffset; dy = 0.0; }
+    if (i == 2) { dx = doffset; dy = 0.0; }
+    if (i == 1) { dx = 0.0; dy = doffset; }
+    if (i == 3) { dx = 0.0; dy = doffset; }
+
+    fx  = graph[0].axis[i].fx - dx;
+    fy  = graph[0].axis[i].fy - dy;
+    dfx = graph[0].axis[i].dfx + 2*dx;
+    dfy = graph[0].axis[i].dfy + 2*dy;
+    P = hypot (graph[0].axis[(i+1)%2].dfx, graph[0].axis[(i+1)%2].dfy);
+    P *= (1 + 0.25*lweight);
+
+    bDrawSetStyle (buffer, color, lweight, 0);
+    // function about sets color and weight
     // bDrawRotTextInit does not exist
 
     if (graph[0].axis[i].isaxis) { 
-      bDrawLine (fx, fy, fx+dfx, fy+dfy); 
+      bDrawLine (buffer, fx, fy, fx+dfx, fy+dfy); 
     }
     
@@ -34,5 +42,10 @@
       ticks = CreateAxisTicks (&graph[0].axis[i], &Nticks);
       for (j = 0; j < Nticks; j++) {
-	bDrawTick (&graph[0].axis[i], P, &ticks[j], i);
+	bDrawTick (buffer, &graph[0].axis[i], P, &ticks[j], i);
+
+	// XXX DrawTick sets the style to (color, 0, 0) for the font
+	// should the font weight stay the same?
+	// XXX probably not needed now:
+	// bDrawSetStyle (buffer, color, lweight, 0);
       }
       FREE (ticks);
@@ -42,5 +55,5 @@
 }
 
-void bDrawTick (Axis *axis, int P, TickMarkData *tick, int naxis) {
+void bDrawTick (bDrawBuffer *buffer, Axis *axis, int P, TickMarkData *tick, int naxis) {
   
   double x, y, dx, dy;
@@ -75,5 +88,5 @@
   dy = dir*size*dfx*n;
   
-  bDrawLine (x, y, x+dx, y+dy);
+  bDrawLine (buffer, x, y, x+dx, y+dy);
 
   if (tick->IsLabel) {
@@ -94,6 +107,6 @@
     yt = fy + (value-min)*dfy/(max - min) + dy;
 
-    PrintTick (string, value, min, max);
-    bDrawRotText (xt, yt, string, pos, 0.0);
+    PrintTick (string, value, min, max, tick->nsignif);
+    bDrawRotText (buffer, xt, yt, string, pos, 0.0);
   }
 }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawImage.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawImage.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawImage.c	(revision 30118)
@@ -0,0 +1,190 @@
+# include "Ximage.h"
+
+# define WHITE_R 255
+# define WHITE_G 255
+# define WHITE_B 255
+# define MY_SWAP_INT(A,B) { int tmp; tmp = A; A = B; B = tmp; }
+
+int bDrawImage (bDrawBuffer *buffer, KapaImageWidget *image, Graphic *graphic) {
+
+  int ii, i, j;
+  int i_start, i_end, j_start, j_end;
+  int I_start, J_start;
+  int dropback;  /* this is a bit of a kludge... */
+  int dx, dy, DX, DY, inDX, inDY, Xs, Ys;
+  int expand_in, expand_out;
+  double expand, Ix, Iy;
+  unsigned char *out_pix;
+  unsigned short *in_pix, *in_pix_ref;
+  unsigned char *pixel1, *pixel2, *pixel3;
+
+  bDrawColor *line_buffer;
+
+  if (image == NULL) return (TRUE);
+
+  ALLOCATE (pixel1, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel2, unsigned char, graphic[0].Npixels);
+  ALLOCATE (pixel3, unsigned char, graphic[0].Npixels);
+
+  /** cmap[i].pixel must be defined even if X is not used **/
+  for (i = 0; i < graphic[0].Npixels; i++) { /* set up pixel array */
+    pixel1[i] = graphic[0].cmap[i].red >> 8;
+    pixel2[i] = graphic[0].cmap[i].green >> 8;
+    pixel3[i] = graphic[0].cmap[i].blue >> 8;
+  }
+
+  assert ((image[0].picture.expand >= 1) || (image[0].picture.expand <= -2));
+  expand = expand_in = expand_out = 1.0;
+  if (image[0].picture.expand > 0) {
+    expand = 1 / (1.0*image[0].picture.expand);
+    expand_out = image[0].picture.expand;
+    expand_in  = 1;
+  }
+  if (image[0].picture.expand < 0) {
+    expand = fabs((double)image[0].picture.expand);
+    expand_out = 1;
+    expand_in  = -image[0].picture.expand;
+  }
+
+  Xs = image[0].picture.x;
+  Ys = image[0].picture.y;
+  dx = image[0].picture.dx;
+  dy = image[0].picture.dy;
+  DX = image[0].image[0].matrix.Naxis[0];
+  DY = image[0].image[0].matrix.Naxis[1];
+
+  if (buffer[0].Nx < Xs + dx) {
+    fprintf (stderr, "invalid condition\n");
+    abort();
+  }
+  if (buffer[0].Ny < Ys + dy) {
+    fprintf (stderr, "invalid condition\n");
+    abort();
+  }
+
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, &image[0].image[0].matrix, &image[0].picture);
+
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, &image[0].image[0].matrix, &image[0].picture);
+
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = image[0].picture.flipx ? I_start - 1 : I_start;
+  Iy = image[0].picture.flipy ? J_start - 1 : J_start;
+
+  inDX = image[0].picture.flipx ? -1 : +1;
+  inDY = image[0].picture.flipy ? -1 : +1;
+
+  dropback = expand_out - (i_end - i_start) % expand_out;
+  if ((i_end - i_start) % expand_out == 0) dropback = 0;
+
+  ALLOCATE (line_buffer, bDrawColor, 3*dx);
+
+  in_pix_ref  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
+
+  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
+
+  /**** fill in bottom area ****/
+  out_pix = line_buffer;
+  for (i = 0; i < dx; i++, out_pix+=3) {
+    out_pix[0] = WHITE_R;
+    out_pix[1] = WHITE_G;
+    out_pix[2] = WHITE_B;
+  }
+  for (j = 0; j < j_start; j++) {
+    memcpy (&buffer[0].pixels[j + Ys][3*Xs], line_buffer, 3*dx);
+  }
+  
+  /*** fill in the image data region ***/
+  for (j = j_start; j < j_end; j+= expand_out, in_pix_ref += inDY*expand_in*DX) {
+    
+    /* create one output image line */
+    in_pix = in_pix_ref;
+    out_pix = line_buffer;
+
+    /**** fill in area to the left of the picture ****/
+    for (i = 0; i < i_start; i++, out_pix+=3) {
+      out_pix[0] = WHITE_R;
+      out_pix[1] = WHITE_G;
+      out_pix[2] = WHITE_B;
+    }
+    
+    /*** fill in the picture region ***/
+    for (i = i_start; i < i_end; i+=expand_out, in_pix += inDX*expand_in) {
+      for (ii = 0; ii < expand_out; ii++, out_pix+=3) {
+	out_pix[0] = pixel1[*in_pix];
+	out_pix[1] = pixel2[*in_pix];
+	out_pix[2] = pixel3[*in_pix];
+      }
+    }
+    
+    /**** fill in area to the right of the picture ****/
+    for (i = i_end; i < dx; i++, out_pix+=3) {
+      out_pix[0] = WHITE_R;
+      out_pix[1] = WHITE_G;
+      out_pix[2] = WHITE_B;
+    }
+
+    /* write out the image line expand_out times */
+    for (i = 0; i < expand_out; i++) {
+      memcpy (&buffer[0].pixels[j + i + Ys][3*Xs], line_buffer, 3*dx);
+    }
+  }
+
+  /**** fill in top area ****/
+  out_pix = line_buffer;
+  for (i = 0; i < dx; i++, out_pix+=3) { 
+    out_pix[0] = WHITE_R;
+    out_pix[1] = WHITE_G;
+    out_pix[2] = WHITE_B;
+  }
+  for (j = j_end; j < dy; j++) {
+    memcpy (&buffer[0].pixels[j + Ys][3*Xs], line_buffer, 3*dx);
+  }
+
+  free (pixel1);
+  free (pixel2);
+  free (pixel3);
+  free (line_buffer);
+
+  return (TRUE);
+}
+
+# if (0)
+
+  /* I need to write the overlay objects on the jpeg image.
+     if i can write / overwrite data in jpeg buffer, then do it here,
+     otherwise i need to create a temporary image buffer, then write the 
+     scanlines to that buffer */
+
+  {
+    int Npalette;
+    png_color *palette;
+    bDrawColor white, color;
+    bDrawBuffer *buffer;
+
+    palette = KapaPNGPalette (&Npalette);
+
+    buffer = bDrawBufferCreate (dx, dy, 1);
+    for (i = 0; i < NOVERLAYS; i++) {
+      if (image[i].overlay[i].active) bDrawOverlay (image, i);
+    }
+
+    white = KapaColorByName ("white");
+    for (j = 0; j < dy; j++) {
+      for (i = 0; i < dx; i++) {
+	color = buffer[0].pixels[j][i];
+	if (color == white) continue;
+	image_buffer[j*3*dx + 3*i + 0] = palette[color].red;
+	image_buffer[j*3*dx + 3*i + 1] = palette[color].green;
+	image_buffer[j*3*dx + 3*i + 2] = palette[color].blue;
+      }
+    }
+    bDrawBufferFree (buffer);
+  }
+
+# endif
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawIt.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawIt.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawIt.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "Ximage.h"
 
-bDrawBuffer *bDrawIt () {
+bDrawBuffer *bDrawIt (png_color *palette, int Npalette, int Nbyte) {
 
   int i, Nsection;
@@ -13,7 +13,6 @@
   black = KapaColorByName ("black");
 
-  buffer = bDrawBufferCreate (graphic->dx, graphic->dy);
-  bDrawSetBuffer (buffer);
-  bDrawSetStyle (black, 0, 0);
+  buffer = bDrawBufferCreate (graphic->dx, graphic->dy, Nbyte, palette, Npalette);
+  bDrawSetStyle (buffer, black, 0, 0);
   
   // reset the sizes for all sections
@@ -21,6 +20,6 @@
   for (i = 0; i < Nsection; i++) {
       section = GetSectionByNumber (i);
-      bDrawGraph (section->graph);
-      // bDrawImage (section->image);
+      bDrawImage (buffer, section->image, graphic);
+      bDrawGraph (buffer, section->graph);
   }
 
@@ -28,9 +27,9 @@
 }
 
-void bDrawGraph (KapaGraphWidget *graph) {
+void bDrawGraph (bDrawBuffer *buffer, KapaGraphWidget *graph) {
   if (graph == NULL) return;
-  bDrawFrame (graph); 
-  bDrawObjects (graph);
-  bDrawLabels (graph);
-  bDrawTextlines (graph);
+  bDrawFrame (buffer, graph); 
+  bDrawObjects (buffer, graph);
+  bDrawLabels (buffer, graph);
+  bDrawTextlines (buffer, graph);
 }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawLabels.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawLabels.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawLabels.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "Ximage.h"
   
-void bDrawLabels (KapaGraphWidget *graph) {
+void bDrawLabels (bDrawBuffer *buffer, KapaGraphWidget *graph) {
   
   int i, pos, x, y, size;
@@ -25,5 +25,5 @@
       y = graph[0].label[i].y;
       SetRotFont (graph[0].label[i].font, graph[0].label[i].size); 
-      bDrawRotText (x, y, graph[0].label[i].text, pos, angle);
+      bDrawRotText (buffer, x, y, graph[0].label[i].text, pos, angle);
     }
   }
@@ -31,5 +31,5 @@
 }
 
-void bDrawTextlines (KapaGraphWidget *graph) {
+void bDrawTextlines (bDrawBuffer *buffer, KapaGraphWidget *graph) {
 
   int i, x, y, size;
@@ -44,5 +44,5 @@
       y = graph[0].textline[i].y;
       SetRotFont (graph[0].textline[i].font, graph[0].textline[i].size);
-      bDrawRotText (x, y, graph[0].textline[i].text, 5, angle);
+      bDrawRotText (buffer, x, y, graph[0].textline[i].text, 5, angle);
     }
   }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawObjects.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawObjects.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawObjects.c	(revision 30118)
@@ -1,10 +1,10 @@
 # include "Ximage.h"
 
-# define DrawLine(X1,Y1,X2,Y2) (bDrawLine ((X1), (Y1), (X2), (Y2)))
-# define DrawCircle(X1,Y1,R) (bDrawCircle ((X1), (Y1), (R)))
-# define DrawRectangle(X,Y,dX,dY) (bDrawRectOpen ((X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
-# define FillRectangle(X,Y,dX,dY) (bDrawRectFill ((X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
-# define FillTriangle(X1,Y1,X2,Y2,X3,Y3) (bDrawTriFill ((X1), (Y1), (X2), (Y2), (X3), (Y3)))
-# define OpenTriangle(X1,Y1,X2,Y2,X3,Y3) (bDrawTriOpen ((X1), (Y1), (X2), (Y2), (X3), (Y3)))
+# define DrawLine(BUF,X1,Y1,X2,Y2) (bDrawLine (BUF, (X1), (Y1), (X2), (Y2)))
+# define DrawCircle(BUF,X1,Y1,R) (bDrawCircle (BUF, (X1), (Y1), (R)))
+# define DrawRectangle(BUF,X,Y,dX,dY) (bDrawRectOpen (BUF, (X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
+# define FillRectangle(BUF,X,Y,dX,dY) (bDrawRectFill (BUF, (X-0.5*dX), (Y-0.5*dY), (X+0.5*dX), (Y+0.5*dY)))
+# define FillTriangle(BUF,X1,Y1,X2,Y2,X3,Y3) (bDrawTriFill (BUF, (X1), (Y1), (X2), (Y2), (X3), (Y3)))
+# define OpenTriangle(BUF,X1,Y1,X2,Y2,X3,Y3) (bDrawTriOpen (BUF, (X1), (Y1), (X2), (Y2), (X3), (Y3)))
 
 # define CONNECT 0
@@ -14,5 +14,5 @@
 static Graphic *graphic;
 
-int bDrawObjects (KapaGraphWidget *graph) {
+int bDrawObjects (bDrawBuffer *buffer, KapaGraphWidget *graph) {
   
   int i;
@@ -30,30 +30,30 @@
     type = graph[0].objects[i].ltype;    
     color = graph[0].objects[i].color;
-    bDrawSetStyle (color, weight, type);
+    bDrawSetStyle (buffer, color, weight, type);
 
     switch (graph[0].objects[i].style) {
       case CONNECT: 
-	bDrawConnect (graph, &graph[0].objects[i]);
+	bDrawConnect (buffer, graph, &graph[0].objects[i]);
 	break;
       case HISTOGRAM:
-	bDrawHistogram (graph, &graph[0].objects[i]);
+	bDrawHistogram (buffer, graph, &graph[0].objects[i]);
 	break;
       case POINTS:
-	bDrawPoints (graph, &graph[0].objects[i]);
+	bDrawPoints (buffer, graph, &graph[0].objects[i]);
 	break;
     }
 
     if (graph[0].objects[i].etype & 0x01) {
-      bDrawYErrors (graph, &graph[0].objects[i]);
+      bDrawYErrors (buffer, graph, &graph[0].objects[i]);
     }
     if (graph[0].objects[i].etype & 0x02) {
-      bDrawXErrors (graph, &graph[0].objects[i]);
-    }
-  }
-  bDrawSetStyle (black, 0, 0);
+      bDrawXErrors (buffer, graph, &graph[0].objects[i]);
+    }
+  }
+  bDrawSetStyle (buffer, black, 0, 0);
   return (TRUE);
 }
 
-void bDrawConnect (KapaGraphWidget *graph, Gobjects *object) {
+void bDrawConnect (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
   
   int i;
@@ -91,10 +91,10 @@
     sx1 = x[i]*mxi + y[i]*mxj + bx;
     sy1 = x[i]*myi + y[i]*myj + by;
-    bDrawClipLine (sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
+    bDrawClipLine (buffer, sx0, sy0, sx1, sy1, X0, Y0, X1, Y1);
     sx0 = sx1; sy0 = sy1;
   }
 }
 
-void bDrawClipLine (double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0) {
+void bDrawClipLine (bDrawBuffer *buffer, double x0, double y0, double x1, double y1, double X0, double Y1, double X1, double Y0) {
 
   /* skip line segement if both points are beyond box */
@@ -145,9 +145,9 @@
     y1 = Y1;
   }
-  DrawLine (x0, y0, x1, y1);
+  DrawLine (buffer, x0, y0, x1, y1);
 }
 
 /*******/
-void bDrawHistogram (KapaGraphWidget *graph, Gobjects *object) {
+void bDrawHistogram (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
 
   int i;
@@ -192,7 +192,7 @@
     sy1 = MAX (MIN (sy1, Y0), Y1);
     sxa = 0.5*(sx0 + sx1);
-    DrawLine (sx0, sy0, sxa, sy0);
-    DrawLine (sxa, sy0, sxa, sy1);
-    DrawLine (sxa, sy1, sx1, sy1);
+    DrawLine (buffer, sx0, sy0, sxa, sy0);
+    DrawLine (buffer, sxa, sy0, sxa, sy1);
+    DrawLine (buffer, sxa, sy1, sx1, sy1);
     sx0 = sx1; sy0 = sy1;
   }
@@ -200,5 +200,5 @@
 
 /*******/
-void bDrawPoints (KapaGraphWidget *graph, Gobjects *object) {
+void bDrawPoints (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
  
   int i;
@@ -233,5 +233,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillRectangle (sx, sy, 2*d*z[i], 2*d*z[i]);
+	  FillRectangle (buffer, sx, sy, 2*d*z[i], 2*d*z[i]);
 	}
       }
@@ -245,5 +245,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawRectangle (sx, sy, 2*d*z[i], 2*d*z[i]);
+	  DrawRectangle (buffer, sx, sy, 2*d*z[i], 2*d*z[i]);
 	}
       }
@@ -257,6 +257,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx - d*z[i], sy, sx + d*z[i], sy);
-	  DrawLine (sx, sy - d*z[i], sx, sy + d*z[i]);
+	  DrawLine (buffer, sx - d*z[i], sy, sx + d*z[i], sy);
+	  DrawLine (buffer, sx, sy - d*z[i], sx, sy + d*z[i]);
 	}
       }
@@ -270,6 +270,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx + d*z[i], sy - d*z[i], sx - d*z[i], sy + d*z[i]);
-	  DrawLine (sx - d*z[i], sy - d*z[i], sx + d*z[i], sy + d*z[i]);
+	  DrawLine (buffer, sx + d*z[i], sy - d*z[i], sx - d*z[i], sy + d*z[i]);
+	  DrawLine (buffer, sx - d*z[i], sy - d*z[i], sx + d*z[i], sy + d*z[i]);
 	}
       }
@@ -283,5 +283,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillTriangle (sx - d*z[i], sy - 0.58*d*z[i], sx + d*z[i], sy - 0.58*d*z[i], sx, sy + 1.15*d*z[i]);
+	  FillTriangle (buffer, sx - d*z[i], sy - 0.58*d*z[i], sx + d*z[i], sy - 0.58*d*z[i], sx, sy + 1.15*d*z[i]);
 	}
       }
@@ -295,5 +295,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  OpenTriangle (sx - d*z[i], sy + 0.58*d*z[i], sx, sy - 1.15*d*z[i], sx + d*z[i], sy + 0.58*d*z[i]);
+	  OpenTriangle (buffer, sx - d*z[i], sy + 0.58*d*z[i], sx, sy - 1.15*d*z[i], sx + d*z[i], sy + 0.58*d*z[i]);
 	}
       }
@@ -307,7 +307,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx, sy, sx - d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (sx, sy, sx + d*z[i], sy + 0.58*d*z[i]);
-	  DrawLine (sx, sy, sx,          sy - 1.15*d*z[i]);
+	  DrawLine (buffer, sx, sy, sx - d*z[i], sy + 0.58*d*z[i]);
+	  DrawLine (buffer, sx, sy, sx + d*z[i], sy + 0.58*d*z[i]);
+	  DrawLine (buffer, sx, sy, sx,          sy - 1.15*d*z[i]);
 	}
       }
@@ -321,5 +321,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawCircle (sx, sy, d*z[i]);
+	  DrawCircle (buffer, sx, sy, d*z[i]);
 	}
       }
@@ -333,9 +333,9 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx + 0.00*d*z[i], sy - 1.00*d*z[i], sx + 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (sx + 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (sx + 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.58*d*z[i], sy + 0.81*d*z[i]);
-	  DrawLine (sx - 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.95*d*z[i], sy - 0.31*d*z[i]);
-	  DrawLine (sx - 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.00*d*z[i], sy - 1.00*d*z[i]);
+	  DrawLine (buffer, sx + 0.00*d*z[i], sy - 1.00*d*z[i], sx + 0.95*d*z[i], sy - 0.31*d*z[i]);
+	  DrawLine (buffer, sx + 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.58*d*z[i], sy + 0.81*d*z[i]);
+	  DrawLine (buffer, sx + 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.58*d*z[i], sy + 0.81*d*z[i]);
+	  DrawLine (buffer, sx - 0.58*d*z[i], sy + 0.81*d*z[i], sx - 0.95*d*z[i], sy - 0.31*d*z[i]);
+	  DrawLine (buffer, sx - 0.95*d*z[i], sy - 0.31*d*z[i], sx + 0.00*d*z[i], sy - 1.00*d*z[i]);
 	}
       }
@@ -349,11 +349,11 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx -      d*z[i], sy,               sx - 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (sx - 0.50*d*z[i], sy + 0.87*d*z[i], sx + 0.50*d*z[i], sy + 0.87*d*z[i]);
-	  DrawLine (sx + 0.50*d*z[i], sy + 0.87*d*z[i], sx +      d*z[i], sy);
-
-	  DrawLine (sx +      d*z[i], sy,               sx + 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (sx + 0.50*d*z[i], sy - 0.87*d*z[i], sx - 0.50*d*z[i], sy - 0.87*d*z[i]);
-	  DrawLine (sx - 0.50*d*z[i], sy - 0.87*d*z[i], sx -      d*z[i], sy);
+	  DrawLine (buffer, sx -      d*z[i], sy,               sx - 0.50*d*z[i], sy + 0.87*d*z[i]);
+	  DrawLine (buffer, sx - 0.50*d*z[i], sy + 0.87*d*z[i], sx + 0.50*d*z[i], sy + 0.87*d*z[i]);
+	  DrawLine (buffer, sx + 0.50*d*z[i], sy + 0.87*d*z[i], sx +      d*z[i], sy);
+
+	  DrawLine (buffer, sx +      d*z[i], sy,               sx + 0.50*d*z[i], sy - 0.87*d*z[i]);
+	  DrawLine (buffer, sx + 0.50*d*z[i], sy - 0.87*d*z[i], sx - 0.50*d*z[i], sy - 0.87*d*z[i]);
+	  DrawLine (buffer, sx - 0.50*d*z[i], sy - 0.87*d*z[i], sx -      d*z[i], sy);
 	}
       }
@@ -366,5 +366,5 @@
 	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
 	sy2 = x[i+1]*myi + y[i+1]*myj + by;
-	DrawLine (sx1, sy1, sx2, sy2);
+	DrawLine (buffer, sx1, sy1, sx2, sy2);
       }
     }
@@ -380,5 +380,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillRectangle (sx, sy, 2*d, 2*d);
+	  FillRectangle (buffer, sx, sy, 2*d, 2*d);
 	}
       }
@@ -392,5 +392,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawRectangle (sx, sy, 2*d, 2*d);
+	  DrawRectangle (buffer, sx, sy, 2*d, 2*d);
 	}
       }
@@ -404,6 +404,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx - d, sy, sx + d, sy);
-	  DrawLine (sx, sy - d, sx, sy + d);
+	  DrawLine (buffer, sx - d, sy, sx + d, sy);
+	  DrawLine (buffer, sx, sy - d, sx, sy + d);
 	}
       }
@@ -417,6 +417,6 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx + d, sy - d, sx - d, sy + d);
-	  DrawLine (sx - d, sy - d, sx + d, sy + d);
+	  DrawLine (buffer, sx + d, sy - d, sx - d, sy + d);
+	  DrawLine (buffer, sx - d, sy - d, sx + d, sy + d);
 	}
       }
@@ -430,5 +430,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  FillTriangle (sx - d, sy - 0.58*d, sx + d, sy - 0.58*d, sx, sy + 1.15*d);
+	  FillTriangle (buffer, sx - d, sy - 0.58*d, sx + d, sy - 0.58*d, sx, sy + 1.15*d);
 	}
       }
@@ -442,5 +442,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  OpenTriangle (sx - d, sy + 0.58*d, sx + d, sy + 0.58*d, sx, sy - 1.15*d);
+	  OpenTriangle (buffer, sx - d, sy + 0.58*d, sx + d, sy + 0.58*d, sx, sy - 1.15*d);
 	}
       }
@@ -454,7 +454,7 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx, sy, sx - d, sy - 0.58*d);
-	  DrawLine (sx, sy, sx + d, sy - 0.58*d);
-	  DrawLine (sx, sy, sx,     sy + 1.15*d);
+	  DrawLine (buffer, sx, sy, sx - d, sy - 0.58*d);
+	  DrawLine (buffer, sx, sy, sx + d, sy - 0.58*d);
+	  DrawLine (buffer, sx, sy, sx,     sy + 1.15*d);
 	}
       }
@@ -468,5 +468,5 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawCircle (sx, sy, d);
+	  DrawCircle (buffer, sx, sy, d);
 	}
       }
@@ -480,9 +480,9 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx + 0.00*d, sy - 1.00*d, sx + 0.95*d, sy - 0.31*d);
-	  DrawLine (sx + 0.95*d, sy - 0.31*d, sx + 0.58*d, sy + 0.81*d);
-	  DrawLine (sx + 0.58*d, sy + 0.81*d, sx - 0.58*d, sy + 0.81*d);
-	  DrawLine (sx - 0.58*d, sy + 0.81*d, sx - 0.95*d, sy - 0.31*d);
-	  DrawLine (sx - 0.95*d, sy - 0.31*d, sx + 0.00*d, sy - 1.00*d);
+	  DrawLine (buffer, sx + 0.00*d, sy - 1.00*d, sx + 0.95*d, sy - 0.31*d);
+	  DrawLine (buffer, sx + 0.95*d, sy - 0.31*d, sx + 0.58*d, sy + 0.81*d);
+	  DrawLine (buffer, sx + 0.58*d, sy + 0.81*d, sx - 0.58*d, sy + 0.81*d);
+	  DrawLine (buffer, sx - 0.58*d, sy + 0.81*d, sx - 0.95*d, sy - 0.31*d);
+	  DrawLine (buffer, sx - 0.95*d, sy - 0.31*d, sx + 0.00*d, sy - 1.00*d);
 	}
       }
@@ -496,10 +496,10 @@
 	    (sy < graph[0].axis[1].fy) && (sy > graph[0].axis[1].fy + graph[0].axis[1].dfy))
 	{
-	  DrawLine (sx - 1.00*d, sy + 0.00*d, sx - 0.50*d, sy + 0.87*d);
-	  DrawLine (sx - 0.50*d, sy + 0.87*d, sx + 0.50*d, sy + 0.87*d);
-	  DrawLine (sx + 0.50*d, sy + 0.87*d, sx + 1.00*d, sy + 0.00*d);
-	  DrawLine (sx + 1.00*d, sy + 0.00*d, sx + 0.50*d, sy - 0.87*d);
-	  DrawLine (sx + 0.50*d, sy - 0.87*d, sx - 0.50*d, sy - 0.87*d);
-	  DrawLine (sx - 0.50*d, sy - 0.87*d, sx - 1.00*d, sy + 0.00*d);
+	  DrawLine (buffer, sx - 1.00*d, sy + 0.00*d, sx - 0.50*d, sy + 0.87*d);
+	  DrawLine (buffer, sx - 0.50*d, sy + 0.87*d, sx + 0.50*d, sy + 0.87*d);
+	  DrawLine (buffer, sx + 0.50*d, sy + 0.87*d, sx + 1.00*d, sy + 0.00*d);
+	  DrawLine (buffer, sx + 1.00*d, sy + 0.00*d, sx + 0.50*d, sy - 0.87*d);
+	  DrawLine (buffer, sx + 0.50*d, sy - 0.87*d, sx - 0.50*d, sy - 0.87*d);
+	  DrawLine (buffer, sx - 0.50*d, sy - 0.87*d, sx - 1.00*d, sy + 0.00*d);
 	}
       }
@@ -512,5 +512,5 @@
 	sx2 = x[i+1]*mxi + y[i+1]*mxj + bx;
 	sy2 = x[i+1]*myi + y[i+1]*myj + by;
-	DrawLine (sx1, sy1, sx2, sy2);
+	DrawLine (buffer, sx1, sy1, sx2, sy2);
       }
     }
@@ -519,5 +519,5 @@
     
 /*******/
-void bDrawXErrors (KapaGraphWidget *graph, Gobjects *object) {
+void bDrawXErrors (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
   
   int i, bar;
@@ -553,9 +553,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      DrawLine (sx0, sy0, sx1, sy1);
+      DrawLine (buffer, sx0, sy0, sx1, sy1);
       if (bar) {
 	sx10 = sy1 - sz;
 	sx11 = sy1 + sz;
-	DrawLine (sx1, sx10, sx1, sx11);
+	DrawLine (buffer, sx1, sx10, sx1, sx11);
       }
     }
@@ -570,9 +570,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      DrawLine (sx0, sy0, sx1, sy1);
+      DrawLine (buffer, sx0, sy0, sx1, sy1);
       if (bar) {
 	sx10 = sy1 - sz;
 	sx11 = sy1 + sz;
-	DrawLine (sx1, sx10, sx1, sx11);
+	DrawLine (buffer, sx1, sx10, sx1, sx11);
       }
     }
@@ -581,5 +581,5 @@
     
 /*******/
-void bDrawYErrors (KapaGraphWidget *graph, Gobjects *object) {
+void bDrawYErrors (bDrawBuffer *buffer, KapaGraphWidget *graph, Gobjects *object) {
   
   int i, bar;
@@ -615,9 +615,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      DrawLine (sx0, sy0, sx1, sy1);
+      DrawLine (buffer, sx0, sy0, sx1, sy1);
       if (bar) {
 	sx10 = sx1 - sz;
 	sx11 = sx1 + sz;
-	DrawLine (sx10, sy1, sx11, sy1);
+	DrawLine (buffer, sx10, sy1, sx11, sy1);
       }
     }
@@ -632,9 +632,9 @@
 	 (sy1 < graph[0].axis[1].fy) && (sy1 > graph[0].axis[1].fy + graph[0].axis[1].dfy)))
     {
-      DrawLine (sx0, sy0, sx1, sy1);
+      DrawLine (buffer, sx0, sy0, sx1, sy1);
       if (bar) {
 	sx10 = sx1 - sz;
 	sx11 = sx1 + sz;
-	DrawLine (sx10, sy1, sx11, sy1);
+	DrawLine (buffer, sx10, sy1, sx11, sy1);
       }
     }
Index: /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawOverlay.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawOverlay.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/kapa2/src/bDrawOverlay.c	(revision 30118)
@@ -4,5 +4,5 @@
 static char name[4][16] = {"red", "green", "blue", "yellow"};
 
-void bDrawOverlay (KapaImageWidget *image, int N) {
+void bDrawOverlay (bDrawBuffer *buffer, KapaImageWidget *image, int N) {
 
   int i;
@@ -14,5 +14,5 @@
   /* translate color to bDrawColors : image[0].overlay[N].color */
   color = KapaColorByName (name[N]);
-  bDrawSetStyle (color, 0, 0);
+  bDrawSetStyle (buffer, color, 0, 0);
   
   expand = 1.0;
@@ -57,14 +57,14 @@
     switch (image[0].overlay[N].objects[i].type) {
       case KII_OVERLAY_LINE:
-	bDrawLine (X, Y, (X+dX), (Y+dY));
+	bDrawLine (buffer, X, Y, (X+dX), (Y+dY));
 	break;
       case KII_OVERLAY_TEXT:
-	bDrawRotText (X, Y, image[0].overlay[N].objects[i].text, 8, 0.0);
+	bDrawRotText (buffer, X, Y, image[0].overlay[N].objects[i].text, 8, 0.0);
 	break;
       case KII_OVERLAY_BOX:
 	dx = MAX (abs(dX),2) / 2;
 	dy = MAX (abs(dY),2) / 2;
-	bDrawRectOpen ((X-dx), (Y-dy), (X+dx), (Y+dy));
-	// bDrawRectOpen ((X-dx), (Y-dy), (X), (Y));
+	bDrawRectOpen (buffer, (X-dx), (Y-dy), (X+dx), (Y+dy));
+	// bDrawRectOpen (buffer, (X-dx), (Y-dy), (X), (Y));
 	break;
       case KII_OVERLAY_CIRCLE:
@@ -72,5 +72,5 @@
 	dy = MAX (abs(dY),2);
 	if (image[0].overlay[N].objects[i].angle == 0.0) {
-	  bDrawArc (X, Y, dx, dy, 0, 360);
+	  bDrawArc (buffer, X, Y, dx, dy, 0, 360);
 	} else {
 	  // moderately-stupid rotated ellipse drawing:
@@ -88,5 +88,5 @@
 	    x1 = X + pX*dx*cos(t)*cs - pX*dy*sin(t)*sn;
 	    y1 = Y + pY*dx*cos(t)*sn + pY*dy*sin(t)*cs;
-	    bDrawLine (x0, y0, x1, y1);
+	    bDrawLine (buffer, x0, y0, x1, y1);
 	    x0 = x1;
 	    y0 = y1;
@@ -101,5 +101,5 @@
   
   /* translate color to bDrawColors : image[0].overlay[N].color */
-  bDrawSetStyle (color, 0, 0);
+  bDrawSetStyle (buffer, color, 0, 0);
 }
 
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/include/dvo.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/include/dvo.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/include/dvo.h	(revision 30118)
@@ -58,10 +58,10 @@
 // these are used as NAN for types of int values
 typedef enum {
-    NAN_S_CHAR  = 0x7f,
-    NAN_U_CHAR  = 0xff,   // was NO_ERR
-    NAN_S_SHORT = 0x7fff, // was NO_MAG
-    NAN_U_SHORT = 0xffff, 
-    NAN_S_INT   = 0x7fffffff,
-    NAN_U_INT   = 0xffffffff,
+  NAN_S_CHAR  = 0x7f,
+  NAN_U_CHAR  = 0xff,   // was NO_ERR
+  NAN_S_SHORT = 0x7fff, // was NO_MAG
+  NAN_U_SHORT = 0xffff, 
+  NAN_S_INT   = 0x7fffffff,
+  NAN_U_INT   = (signed int) 0xffffffff,
 } DVO_INT_NAN;
 
@@ -135,17 +135,17 @@
 /* Average.code values -- these values are 32 bit (as of PS1_V1) */
 typedef enum {
-  ID_STAR_FEW     = 0x00000001, // used within relphot: skip star 
-  ID_STAR_POOR    = 0x00000002, // used within relphot: skip star 
-  ID_PROPER       = 0x00000400, // star with large proper motion 
-  ID_TRANSIENT    = 0x00001000, // is this mutually exclusive with USNO?  
-  ID_VARIABLE     = 0x00002000, // not currently set? 
-  ID_ASTEROID     = 0x00002000, // identified with an asteroid 
-  ID_BAD_OBJECT   = 0x00004000, // if all measurements are bad, set this bit 
+  ID_STAR_FEW     = 0x00000001, // used within relphot: skip star
+  ID_STAR_POOR    = 0x00000002, // used within relphot: skip star
+  ID_PROPER       = 0x00000400, // star with large proper motion
+  ID_TRANSIENT    = 0x00001000, // is this mutually exclusive with USNO?
+  ID_VARIABLE     = 0x00002000, // not currently set?
+  ID_ASTEROID     = 0x00002000, // identified with an asteroid
+  ID_BAD_OBJECT   = 0x00004000, // if all measurements are bad, set this bit
   ID_MOVING       = 0x00008000, // is a moving object
-  ID_ROCK         = 0x0000a000, // 0x8000 + 0x2000 
-  ID_GHOST        = 0x0000c001, // 0x8000 + 0x4000 + 0x0001 
-  ID_TRAIL        = 0x0000c002, // 0x8000 + 0x4000 + 0x0002 
-  ID_BLEED        = 0x0000c003, // 0x8000 + 0x4000 + 0x0003  
-  ID_COSMIC       = 0x0000c004, // 0x8000 + 0x4000 + 0x0004  
+  ID_ROCK         = 0x0000a000, // 0x8000 + 0x2000
+  ID_GHOST        = 0x0000c001, // 0x8000 + 0x4000 + 0x0001
+  ID_TRAIL        = 0x0000c002, // 0x8000 + 0x4000 + 0x0002
+  ID_BLEED        = 0x0000c003, // 0x8000 + 0x4000 + 0x0003
+  ID_COSMIC       = 0x0000c004, // 0x8000 + 0x4000 + 0x0004
   ID_STAR_FIT_AVE = 0x00010000, // average position fitted
   ID_STAR_FIT_PM  = 0x00020000, // proper motion fitted
@@ -156,6 +156,6 @@
   ID_OBJ_EXT      = 0x01000000, // extended in our data (eg, PS)
   ID_OBJ_EXT_ALT  = 0x02000000, // extended in external data (eg, 2MASS)
-  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     = 0x04000000, // good-quality measurement in our data (eg,PS)
+  ID_OBJ_GOOD_ALT = 0x08000000, // good-quality measurement in  external data (eg, 2MASS)
 } DVOAverageFlags;
 
@@ -233,5 +233,5 @@
      *** that is just silly, and bad: convert to using Nsec_mem, Nsec_disk, Nsec_off.
      *** unless we always require the secfilt and average entries to be loaded sychronously.
-   */
+     */
 
   /* pointers to split data files */
@@ -293,4 +293,5 @@
 int isRegisteredMosaic (void);
 off_t GetRegisteredMosaic (void);
+off_t *GetChipMatch (void);
 int GetMosaicCoords (Coords *coords);
 int FindMosaicForImage (Image *images, off_t Nimages, off_t entry);
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog.c	(revision 30118)
@@ -302,4 +302,6 @@
 int dvo_catalog_save (Catalog *catalog, char VERBOSE) {
 
+  int status = FALSE;
+
   // set the 'sorted' header keyword
   gfits_modify_alt (&catalog[0].header, "SORTED",  "%t", 1, catalog[0].sorted);
@@ -308,11 +310,11 @@
   switch (catalog[0].catmode) {
     case DVO_MODE_RAW:
-      dvo_catalog_save_raw (catalog, VERBOSE);
+      status = dvo_catalog_save_raw (catalog, VERBOSE);
       break;
     case DVO_MODE_MEF:
-      dvo_catalog_save_mef (catalog, VERBOSE);
+      status = dvo_catalog_save_mef (catalog, VERBOSE);
       break;
     case DVO_MODE_SPLIT:
-      dvo_catalog_save_split (catalog, VERBOSE);
+      status = dvo_catalog_save_split (catalog, VERBOSE);
       break;
     default:
@@ -320,5 +322,5 @@
       exit (2);
   }
-  return (TRUE);
+  return (status);
 }
 
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_mef.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_mef.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_mef.c	(revision 30118)
@@ -66,5 +66,5 @@
   /* read Average table data (or skip) */
   if (catalog[0].catflags & LOAD_AVES) {
-    if (!gfits_fread_ftable_data (f, &ftable)) {
+    if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table average data");
       return (FALSE);
@@ -94,5 +94,5 @@
   /* read Measure table data */
   if (catalog[0].catflags & LOAD_MEAS) {
-    if (!gfits_fread_ftable_data (f, &ftable)) {
+    if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table measure data");
       return (FALSE);
@@ -119,5 +119,5 @@
   /* read Missing table data */
   if (catalog[0].catflags & LOAD_MISS) {
-    if (!gfits_fread_ftable_data (f, &ftable)) {
+    if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table missing data");
       return (FALSE);
@@ -149,5 +149,5 @@
   /* read secfilt table data */
   if (catalog[0].catflags & LOAD_SECF) {
-    if (!gfits_fread_ftable_data (f, &ftable)) {
+    if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table secfilt data");
       return (FALSE);
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_split.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 30118)
@@ -218,5 +218,5 @@
     }
     /* read Average table data : format is irrelevant here */
-    if (!gfits_fread_ftable_data (catalog[0].f, &ftable)) { 
+    if (!gfits_fread_ftable_data (catalog[0].f, &ftable, FALSE)) { 
       if (VERBOSE) fprintf (stderr, "can't read table average data");
       return (FALSE);
@@ -249,5 +249,5 @@
     // XXX this allows an empty Measure catalog with non-empty Average catalog : is that OK?
     /* read Measure table data */
-    if (!gfits_fread_ftable_data (catalog[0].measure_catalog[0].f, &ftable)) {
+    if (!gfits_fread_ftable_data (catalog[0].measure_catalog[0].f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table measure data\n");
       return (FALSE);
@@ -279,5 +279,5 @@
   if ((status != DVO_CAT_OPEN_EMPTY) && (catalog[0].catflags & LOAD_MISS)) {
     /* read Missing table data */
-    if (!gfits_fread_ftable_data (catalog[0].missing_catalog[0].f, &ftable)) {
+    if (!gfits_fread_ftable_data (catalog[0].missing_catalog[0].f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table missing data\n");
       return (FALSE);
@@ -313,5 +313,5 @@
   if ((status != DVO_CAT_OPEN_EMPTY) && (catalog[0].catflags & LOAD_SECF)) {
     /* read secfilt table data */
-    if (!gfits_fread_ftable_data (catalog[0].secfilt_catalog[0].f, &ftable)) {
+    if (!gfits_fread_ftable_data (catalog[0].secfilt_catalog[0].f, &ftable, FALSE)) {
       if (VERBOSE) fprintf (stderr, "can't read table secfilt data\n");
       return (FALSE);
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_photcode_ops.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 30118)
@@ -557,9 +557,11 @@
       }
     }
-    if (entry == -1) {
-      // entry is missing fail (no printfs in this file)
-      free(map);
-      return(FALSE);
-    }
+    // if (entry == -1) {
+    //   // entry is missing fail (no printfs in this file)
+    //   free(map);
+    //   return(FALSE);
+    // }
+
+    // if entry is still -1, we will skip this one (not map into the output db)
     map[i] = entry;
   }
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/fits_db.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/fits_db.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/fits_db.c	(revision 30118)
@@ -83,5 +83,5 @@
     return (FALSE);
   }
-  if (!gfits_fread_ftable_data (db[0].f, &db[0].ftable)) {
+  if (!gfits_fread_ftable_data (db[0].f, &db[0].ftable, FALSE)) {
     fprintf (stderr, "can't read table data");
     gfits_db_free (db);
Index: /branches/czw_branch/20101203/Ohana/src/libdvo/src/mosaic_astrom.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libdvo/src/mosaic_astrom.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libdvo/src/mosaic_astrom.c	(revision 30118)
@@ -17,4 +17,9 @@
 }
 
+/* what is the currently registered mosaic image? */
+off_t *GetChipMatch () {
+  return (ChipMatch);
+}
+
 /* given an image array and a current entry of type WRP, find matching DIS & Register it */
 int FindMosaicForImage (Image *images, off_t Nimages, off_t entry) {
@@ -40,5 +45,5 @@
   if (strcmp(&images[entry].coords.ctype[4], "-WRP")) {
     /* not a wrp image, do nothing */
-    return (TRUE); /* error or not */
+    return (entry + 1); /* error or not */
   }
 
@@ -52,5 +57,5 @@
     RegisterMosaic (&images[i].coords);
     iDIS = i;
-    return (TRUE);
+    return (i + 1);
   }
 
@@ -62,5 +67,5 @@
     RegisterMosaic (&images[i].coords);
     iDIS = i;
-    return (TRUE);
+    return (i + 1);
   }
   return (FALSE);
@@ -74,5 +79,5 @@
   if (strcmp(&images[entry].coords.ctype[4], "-WRP")) {
     /* not a wrp image, do nothing */
-    return (TRUE); /* error or not? */
+    return (entry + 1); /* error or not? */
   }
 
@@ -85,5 +90,5 @@
   RegisterMosaic (&images[N].coords);
   iDIS = N;
-  return (TRUE);
+  return (N + 1);
 }
 
@@ -165,8 +170,18 @@
   SortDISindex (DIStzero, DISentry, Ndis);
 
+  // ChipMatch has a few possible values: 
+  // -3 : image is a mosaic (DIS)
+  // -2 : image is an unassigned WRP image
+  // -1 : image is not a WRP or DIS images
+  // >= 0 : value is the mosaic seq number for this WRP image 
+
   /* find all matched WRP images */
   ALLOCATE (ChipMatch, off_t, Nimages);
   for (i = 0; i < Nimages; i++) {
     ChipMatch[i] = -1;
+    if (!strcmp(&images[i].coords.ctype[4], "-DIS")) {
+      ChipMatch[i] = -3;
+      continue;
+    }
     if (strcmp(&images[i].coords.ctype[4], "-WRP")) continue;
 
Index: /branches/czw_branch/20101203/Ohana/src/libfits/include/gfitsio.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libfits/include/gfitsio.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libfits/include/gfitsio.h	(revision 30118)
@@ -64,4 +64,5 @@
   char                   *buffer;
   off_t                   datasize;
+  off_t                   validsize;
 } FTable;
 
@@ -172,5 +173,5 @@
 int     gfits_define_table_column      PROTO((Header *header, char *format, char *label, char *comment, char *unit));
 int   	gfits_fread_ftable             PROTO((FILE *f, FTable *ftable, char *extname)); 
-int   	gfits_fread_ftable_data        PROTO((FILE *f, FTable *ftable));
+int   	gfits_fread_ftable_data        PROTO((FILE *f, FTable *ftable, int padIfShort));
 int   	gfits_fread_ftable_range       PROTO((FILE *f, FTable *ftable, off_t start, off_t Nrows));
 int   	gfits_fread_vtable             PROTO((FILE *f, VTable *vtable, char *extname, off_t Nrow, off_t *row));
Index: /branches/czw_branch/20101203/Ohana/src/libfits/table/F_read_T.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libfits/table/F_read_T.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libfits/table/F_read_T.c	(revision 30118)
@@ -36,5 +36,5 @@
     gfits_scan (header, "EXTNAME", "%s", 1, tname);
     if (!strcmp (tname, extname)) {
-      if (gfits_fread_ftable_data (f, table)) return (TRUE);
+      if (gfits_fread_ftable_data (f, table, FALSE)) return (TRUE);
       gfits_free_header (header);
       return (FALSE);
@@ -50,5 +50,5 @@
 
 /*********************** fits read ftable data ***********************************/
-int gfits_fread_ftable_data (FILE *f, FTable *table) {
+int gfits_fread_ftable_data (FILE *f, FTable *table, int padIfShort) {
 
   off_t Nbytes, Nread;
@@ -65,9 +65,18 @@
     if (Nread < gfits_data_min_size (table[0].header)) {
       fprintf (stderr, "error: fits read error in %s, read "OFF_T_FMT", need "OFF_T_FMT"\n", __func__,  Nread,  gfits_data_min_size (table[0].header));
-      gfits_free_table  (table);
-      return (FALSE);
+      if (padIfShort) {
+	memset (&table[0].buffer[Nread], 0, Nbytes - Nread);
+	fprintf (stderr, "warning: file missing data, padding with zeros: USE AT YOUR OWN RISK!\n");
+	table[0].validsize = Nread;
+	table[0].datasize = Nbytes;
+	return (TRUE);
+      } else {
+	gfits_free_table  (table);
+	return (FALSE);
+      }
     }
     fprintf (stderr, "warning: file missing pad\n");
   }
+  table[0].validsize = Nread;
   table[0].datasize = Nbytes;
   return (TRUE);
Index: /branches/czw_branch/20101203/Ohana/src/libkapa/include/kapa.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libkapa/include/kapa.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libkapa/include/kapa.h	(revision 30118)
@@ -115,6 +115,15 @@
 
 typedef struct {
-  int Nx, Ny;
+  int Nx, Ny, Nbyte;
   bDrawColor **pixels;
+  png_color *palette;
+  int Npalette;
+  // current drawing values:
+  int bWeight;
+  int bType;
+  bDrawColor bColor;
+  bDrawColor bColor_R;
+  bDrawColor bColor_G;
+  bDrawColor bColor_B;
 } bDrawBuffer;
 
@@ -165,4 +174,5 @@
 /* KapaWindow.c */
 int KiiResize (int fd, int Nx, int Ny);
+int KiiResizeByImage (int fd);
 int KiiRelocate (int fd, int x, int y);
 int KiiCenter (int fd, double x, double y, int zoom);
@@ -182,4 +192,5 @@
 int KapaGetLimits (int fd, float *dx, float *dy);
 int KapaSetSection (int fd, KapaSection *section);
+int KapaSetSectionByImage (int fd, KapaSection *section);
 int KapaSelectSection (int fd, char *name);
 int KapaGetSection (int fd, char *name);
@@ -221,29 +232,29 @@
 
 /* bDrawFuncs.c */
-bDrawBuffer *bDrawBufferCreate (int Nx, int Ny);
+bDrawBuffer *bDrawBufferCreate (int Nx, int Ny, int Nbyte, png_color *palette, int Npalette);
 void bDrawBufferFree (bDrawBuffer *buffer);
 void bDrawSetBuffer (bDrawBuffer *buffer);
-void bDrawSetStyle (bDrawColor color, int lw, int lt);
-void bDrawPoint (int x, int y);
-void bDrawPointf (float x, float y);
-
-void bDrawArc (double Xc, double Yc, double Xr, double Yr, double Ts, double Te);
-void bDrawCircle (double Xc, double Yc, double radius);
-void bDrawCircleFill (double xc, double yc, double radius);
-
-void bDrawLine (double x1, double y1, double x2, double y2);
-void bDrawLineWeight (int X1, int Y1, int X2, int Y2, int swapcoords);
-void bDrawLineBresen (int X1, int Y1, int X2, int Y2, int swapcoords);
-void bDrawLineHorizontal (int X1, int X2, int Y);
-void bDrawLineVertical (int X, int Y1, int Y2);
-
-void bDrawRectOpen (double x1, double y1, double x2, double y2);
-void bDrawRectFill (double x1, double y1, double x2, double y2);
-void bDrawTriOpen (double x1, double y1, double x2, double y2, double x3, double y3);
-void bDrawTriFill (double x1, double y1, double x2, double y2, double x3, double y3);
+void bDrawSetStyle (bDrawBuffer *buffer, bDrawColor color, int lw, int lt);
+void bDrawPoint (bDrawBuffer *buffer, int x, int y);
+void bDrawPointf (bDrawBuffer *buffer, float x, float y);
+
+void bDrawArc (bDrawBuffer *buffer, double Xc, double Yc, double Xr, double Yr, double Ts, double Te);
+void bDrawCircle (bDrawBuffer *buffer, double Xc, double Yc, double radius);
+void bDrawCircleFill (bDrawBuffer *buffer, double xc, double yc, double radius);
+
+void bDrawLine (bDrawBuffer *buffer, double x1, double y1, double x2, double y2);
+void bDrawLineWeight (bDrawBuffer *buffer, int X1, int Y1, int X2, int Y2, int swapcoords);
+void bDrawLineBresen (bDrawBuffer *buffer, int X1, int Y1, int X2, int Y2, int swapcoords);
+void bDrawLineHorizontal (bDrawBuffer *buffer, int X1, int X2, int Y);
+void bDrawLineVertical (bDrawBuffer *buffer, int X, int Y1, int Y2);
+
+void bDrawRectOpen (bDrawBuffer *buffer, double x1, double y1, double x2, double y2);
+void bDrawRectFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2);
+void bDrawTriOpen  (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3);
+void bDrawTriFill  (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3);
 
 /* bDrawRotFont.c */
-int bDrawRotText (int x, int y, char *string, int pos, double angle);
-int bDrawRotBitmap (int x, int y, int dx, int dy, unsigned char *bitmap, int mode, double angle, double scale);
+int bDrawRotText (bDrawBuffer *buffer, int x, int y, char *string, int pos, double angle);
+int bDrawRotBitmap (bDrawBuffer *buffer, int x, int y, int dx, int dy, unsigned char *bitmap, int mode, double angle, double scale);
 
 /* Kapa Socket functions */
Index: /branches/czw_branch/20101203/Ohana/src/libkapa/src/KapaWindow.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libkapa/src/KapaWindow.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libkapa/src/KapaWindow.c	(revision 30118)
@@ -23,4 +23,11 @@
   KiiSendCommand (fd, 4, "RSIZ");
   KiiSendMessage (fd, "%d %d", Nx, Ny); 
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
+int KiiResizeByImage (int fd) {
+
+  KiiSendCommand (fd, 4, "ISIZ");
   KiiWaitAnswer (fd, "DONE");
   return (TRUE);
@@ -370,4 +377,16 @@
 }
 
+int KapaSetSectionByImage (int fd, KapaSection *section) {
+
+  KiiSendCommand (fd, 4, "ISEC");
+  KiiSendMessage (fd, "%s %6.3f %6.3f %3d", 
+		  section[0].name, 
+		  section[0].x,
+		  section[0].y,
+		  section[0].bg);
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
 int KapaSectionBG (int fd, char *name, int bg) {
 
Index: /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawFuncs.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawFuncs.c	(revision 30118)
@@ -1,33 +1,58 @@
 # include <kapa_internal.h>
-
-// XXX we can get rid of these static vars by making them elements of the bDrawBuffer
-// 
-
-
-static int bWeight;
-static int bType;
-static bDrawColor bColor;
-static bDrawBuffer *bBuffer;
-void bDrawCircleSingle (double xc, double yc, double radius);
-
-bDrawBuffer *bDrawBufferCreate (int Nx, int Ny) {
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort (); } }
+
+// move these to the bDrawBuffer type
+// static int bWeight;
+// static int bType;
+// static bDrawColor bColor;
+// static bDrawColor bColor_R;
+// static bDrawColor bColor_G;
+// static bDrawColor bColor_B;
+// static bDrawBuffer *bBuffer;
+
+void bDrawCircleSingle (bDrawBuffer *buffer, double xc, double yc, double radius);
+
+// create a drawing buffer with either 1 or 3 byte colors
+bDrawBuffer *bDrawBufferCreate (int Nx, int Ny, int Nbyte, png_color *palette, int Npalette) {
 
   int i, j;
-  bDrawColor white;
+  bDrawColor white, white_R, white_G, white_B;
   bDrawBuffer *buffer;
 
+  myAssert((Nbyte == 1) || (Nbyte == 3), "invalid depth");
+  myAssert(palette, "missing palette");
+
   white = KapaColorByName ("white");
+  white_R = palette[white].red;
+  white_G = palette[white].green;
+  white_B = palette[white].blue;
 
   ALLOCATE (buffer, bDrawBuffer, 1);
   buffer[0].Nx = Nx;
   buffer[0].Ny = Ny;
+  buffer[0].Nbyte = Nbyte;
+  buffer[0].palette = palette;
+  buffer[0].Npalette = Npalette;
 
   ALLOCATE (buffer[0].pixels, bDrawColor *, Ny);
   for (i = 0; i < Ny; i++) {
-    ALLOCATE (buffer[0].pixels[i], bDrawColor, Nx);
+    ALLOCATE (buffer[0].pixels[i], bDrawColor, Nbyte*Nx);
     for (j = 0; j < Nx; j++) {
-      buffer[0].pixels[i][j] = white;
-    }
-  }
+      if (Nbyte == 1) {
+	buffer[0].pixels[i][j] = white;
+      } else {
+	buffer[0].pixels[i][3*j+0] = white_R;
+	buffer[0].pixels[i][3*j+1] = white_G;
+	buffer[0].pixels[i][3*j+2] = white_B;
+      }
+    }
+  }
+
+  buffer[0].bWeight = 0;
+  buffer[0].bType = 0;
+  buffer[0].bColor = white;
+  buffer[0].bColor_R = white_R;
+  buffer[0].bColor_G = white_G;
+  buffer[0].bColor_B = white_B;
   return (buffer);
 }
@@ -41,48 +66,60 @@
   }
   free (buffer[0].pixels);
+  free (buffer[0].palette);
   free (buffer);
   return;
 }
 
-void bDrawSetBuffer (bDrawBuffer *buffer) {
-  bBuffer = buffer;
-  return;
-}
-
-void bDrawSetStyle (bDrawColor color, int lw, int lt) {
-  bColor = color;
-  bWeight = lw;
-  bType = lt;
+// void bDrawSetBuffer (bDrawBuffer *buffer) {
+//   myAssert(buffer[0].Nbyte == 1, "invalid depth");
+//   bBuffer = buffer;
+//   return;
+// }
+
+void bDrawSetStyle (bDrawBuffer *buffer, bDrawColor color, int lw, int lt) {
+  buffer->bColor = color;
+  buffer->bColor_R = buffer->palette[color].red;
+  buffer->bColor_G = buffer->palette[color].green;
+  buffer->bColor_B = buffer->palette[color].blue;
+  buffer->bWeight = lw;
+  buffer->bType = lt;
   return;
 }
 
 // draw a point in the current color 
-void bDrawPoint (int x, int y) {
-
+void bDrawPoint (bDrawBuffer *buffer, int x, int y) {
+
+  // myAssert(buffer[0].Nbyte == 1, "invalid depth");
   if (x < 0) return;
   if (y < 0) return;
-  if (x >= bBuffer[0].Nx) return;
-  if (y >= bBuffer[0].Ny) return;
-  bBuffer[0].pixels[y][x] = bColor;
+  if (x >= buffer[0].Nx) return;
+  if (y >= buffer[0].Ny) return;
+  if (buffer[0].Nbyte == 1) {
+    buffer[0].pixels[y][x] = buffer->bColor;
+  } else {
+    buffer[0].pixels[y][3*x+0] = buffer->bColor_R;
+    buffer[0].pixels[y][3*x+1] = buffer->bColor_G;
+    buffer[0].pixels[y][3*x+2] = buffer->bColor_B;
+  }
   return;
 }
 
 // draw a point in the current color 
-void bDrawPointf (float x, float y) {
-
-  bDrawPoint (ROUND(x), ROUND(y));
-  return;
-}
-
-void bDrawTriOpen (double x1, double y1, double x2, double y2, double x3, double y3) {
-
-  bDrawLine (x1, y1, x2, y2);
-  bDrawLine (x2, y2, x3, y3);
-  bDrawLine (x3, y3, x1, y1);
-
-  return;
-}
-
-void bDrawRectOpen (double x1, double y1, double x2, double y2) {
+void bDrawPointf (bDrawBuffer *buffer, float x, float y) {
+
+  bDrawPoint (buffer, ROUND(x), ROUND(y));
+  return;
+}
+
+void bDrawTriOpen (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3) {
+
+  bDrawLine (buffer, x1, y1, x2, y2);
+  bDrawLine (buffer, x2, y2, x3, y3);
+  bDrawLine (buffer, x3, y3, x1, y1);
+
+  return;
+}
+
+void bDrawRectOpen (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
 
   int X1, Y1, X2, Y2;
@@ -91,18 +128,18 @@
   if (y1 > y2) SWAP (y1, y2);
 
-  X1 = MIN (MAX (ROUND (x1), 0), bBuffer[0].Nx - 1);
-  X2 = MIN (MAX (ROUND (x2), 1), bBuffer[0].Nx);
-
-  Y1 = MIN (MAX (ROUND (y1), 0), bBuffer[0].Ny - 1);
-  Y2 = MIN (MAX (ROUND (y2), 1), bBuffer[0].Ny);
-
-  bDrawLineHorizontal (X1, X2, Y1);
-  bDrawLineHorizontal (X1, X2, Y2);
-  bDrawLineVertical (X1, Y1, Y2);
-  bDrawLineVertical (X2, Y1, Y2);
-  return;
-}
-
-void bDrawRectFill (double x1, double y1, double x2, double y2) {
+  X1 = MIN (MAX (ROUND (x1), 0), buffer[0].Nx - 1);
+  X2 = MIN (MAX (ROUND (x2), 1), buffer[0].Nx - 1);
+
+  Y1 = MIN (MAX (ROUND (y1), 0), buffer[0].Ny - 1);
+  Y2 = MIN (MAX (ROUND (y2), 1), buffer[0].Ny - 1);
+
+  bDrawLineHorizontal (buffer, X1, X2, Y1);
+  bDrawLineHorizontal (buffer, X1, X2, Y2);
+  bDrawLineVertical   (buffer, X1, Y1, Y2);
+  bDrawLineVertical   (buffer, X2, Y1, Y2);
+  return;
+}
+
+void bDrawRectFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
 
   int i;
@@ -112,12 +149,12 @@
   if (y1 > y2) SWAP (y1, y2);
 
-  X1 = MIN (MAX (ROUND (x1), 0), bBuffer[0].Nx - 1);
-  X2 = MIN (MAX (ROUND (x2), 1), bBuffer[0].Nx);
-
-  Y1 = MIN (MAX (ROUND (y1), 0), bBuffer[0].Ny - 1);
-  Y2 = MIN (MAX (ROUND (y2), 0), bBuffer[0].Ny);
+  X1 = MIN (MAX (ROUND (x1), 0), buffer[0].Nx - 1);
+  X2 = MIN (MAX (ROUND (x2), 1), buffer[0].Nx - 1);
+
+  Y1 = MIN (MAX (ROUND (y1), 0), buffer[0].Ny - 1);
+  Y2 = MIN (MAX (ROUND (y2), 0), buffer[0].Ny - 1);
 
   for (i = Y1; i < Y2; i++) {
-    bDrawLineHorizontal (X1, X2, i);
+    bDrawLineHorizontal (buffer, X1, X2, i);
   } 
   return;
@@ -125,5 +162,5 @@
 
 // identify the quadrant and draw the correct line
-void bDrawLine (double x1, double y1, double x2, double y2) {
+void bDrawLine (bDrawBuffer *buffer, double x1, double y1, double x2, double y2) {
 
   int FlipDirect, FlipCoords;
@@ -144,8 +181,8 @@
   FlipDirect = FlipCoords ? (y1 > y2) : (x1 > x2);
 
-  if (!FlipDirect && !FlipCoords) bDrawLineWeight (X1, Y1, X2, Y2, FALSE);
-  if ( FlipDirect && !FlipCoords) bDrawLineWeight (X2, Y2, X1, Y1, FALSE);
-  if (!FlipDirect &&  FlipCoords) bDrawLineWeight (Y1, X1, Y2, X2, TRUE);
-  if ( FlipDirect &&  FlipCoords) bDrawLineWeight (Y2, X2, Y1, X1, TRUE);
+  if (!FlipDirect && !FlipCoords) bDrawLineWeight (buffer, X1, Y1, X2, Y2, FALSE);
+  if ( FlipDirect && !FlipCoords) bDrawLineWeight (buffer, X2, Y2, X1, Y1, FALSE);
+  if (!FlipDirect &&  FlipCoords) bDrawLineWeight (buffer, Y1, X1, Y2, X2, TRUE);
+  if ( FlipDirect &&  FlipCoords) bDrawLineWeight (buffer, Y2, X2, Y1, X1, TRUE);
 
   return;
@@ -153,16 +190,16 @@
 
 // draw a series of lines to give the line weight
-void bDrawLineWeight (int X1, int Y1, int X2, int Y2, int swapcoords) {
+void bDrawLineWeight (bDrawBuffer *buffer, int X1, int Y1, int X2, int Y2, int swapcoords) {
 
   int dN, dNs, dNe;
 
-  dNs = -0.5*(bWeight - 1); 
+  dNs = -0.5*(buffer->bWeight - 1); 
   /* 0, 0, 0, -1, -1, -2, -2 */
 
-  dNe = +0.5*bWeight + 1; 
+  dNe = +0.5*buffer->bWeight + 1; 
   /* 1, 1, 2, 2, 2, 3, 3 */
 
   for (dN = dNs; dN < dNe; dN++) {
-    bDrawLineBresen (X1, Y1 + dN, X2, Y2 + dN, swapcoords);
+    bDrawLineBresen (buffer, X1, Y1 + dN, X2, Y2 + dN, swapcoords);
   }
   return;
@@ -171,5 +208,5 @@
 // use the Bresenham line drawing technique
 // integer-only Bresenham line-draw version which is fast
-void bDrawLineBresen (int X1, int Y1, int X2, int Y2, int swapcoords) {
+void bDrawLineBresen (bDrawBuffer *buffer, int X1, int Y1, int X2, int Y2, int swapcoords) {
 
   int X, Y, dX, dY;
@@ -185,10 +222,10 @@
   e = 0;
   for (X = X1, N = 0; X <= X2; X++, N++) {
-    if (bType == 1) { DashOn = (N % 10) < 5; }
-    if (bType == 2) { DashOn = (N % 6) < 3; }
+    if (buffer->bType == 1) { DashOn = (N % 10) < 5; }
+    if (buffer->bType == 2) { DashOn = (N % 6) < 3; }
     if (swapcoords) {
-      if (DashOn) bDrawPoint (Y,X);
+      if (DashOn) bDrawPoint (buffer, Y,X);
     } else {
-      if (DashOn) bDrawPoint (X,Y);
+      if (DashOn) bDrawPoint (buffer, X,Y);
     }
     e += dY;
@@ -206,31 +243,43 @@
 }
 
-void bDrawLineHorizontal (int X1, int X2, int Y) {
+void bDrawLineHorizontal (bDrawBuffer *buffer, int X1, int X2, int Y) {
   
   int i;
 
   for (i = X1; i < X2; i++) {
-    bBuffer[0].pixels[Y][i] = bColor;
-  }
-  return;
-}
-
-void bDrawLineVertical (int X, int Y1, int Y2) {
+    if (buffer[0].Nbyte == 1) {
+      buffer[0].pixels[Y][i] = buffer->bColor;
+    } else {
+      buffer[0].pixels[Y][3*i+0] = buffer->bColor_R;
+      buffer[0].pixels[Y][3*i+1] = buffer->bColor_G;
+      buffer[0].pixels[Y][3*i+2] = buffer->bColor_B;
+    }
+  }
+  return;
+}
+
+void bDrawLineVertical (bDrawBuffer *buffer, int X, int Y1, int Y2) {
   
   int i;
 
   for (i = Y1; i < Y2; i++) {
-    bBuffer[0].pixels[i][X] = bColor;
-  }
-  return;
-}
-
-void bDrawTriFill (double x1, double y1, double x2, double y2, double x3, double y3) {
-
-  bDrawTriOpen (x1, y1, x2, y2, x3, y3);
-  return;
-}
-
-void bDrawArc (double Xc, double Yc, double Xr, double Yr, double Ts, double Te) {
+    if (buffer[0].Nbyte == 1) {
+      buffer[0].pixels[i][X] = buffer->bColor;
+    } else {
+      buffer[0].pixels[i][3*X+0] = buffer->bColor_R;
+      buffer[0].pixels[i][3*X+1] = buffer->bColor_G;
+      buffer[0].pixels[i][3*X+2] = buffer->bColor_B;
+    }
+  }
+  return;
+}
+
+void bDrawTriFill (bDrawBuffer *buffer, double x1, double y1, double x2, double y2, double x3, double y3) {
+
+  bDrawTriOpen (buffer, x1, y1, x2, y2, x3, y3);
+  return;
+}
+
+void bDrawArc (bDrawBuffer *buffer, double Xc, double Yc, double Xr, double Yr, double Ts, double Te) {
 
   float t, dt;
@@ -258,5 +307,5 @@
 
     /* we could use the value of MAX(dy/dt,dx/dt) to set dt */
-    bDrawPoint (x,y);
+    bDrawPoint (buffer, x,y);
 
     dt = MAX (fabs(Xr * sin(t)), fabs(Yr * cos(t)));
@@ -267,16 +316,16 @@
 
 // draw a series of circles to give line weight
-void bDrawCircle (double xc, double yc, double radius) {
+void bDrawCircle (bDrawBuffer *buffer, double xc, double yc, double radius) {
 
   int dN, dNs, dNe;
 
-  dNs = -0.5*(bWeight - 1); 
+  dNs = -0.5*(buffer->bWeight - 1); 
   /* 0, 0, 0, -1, -1, -2, -2 */
 
-  dNe = +0.5*bWeight + 1; 
+  dNe = +0.5*buffer->bWeight + 1; 
   /* 1, 1, 2, 2, 2, 3, 3 */
 
   for (dN = dNs; dN < dNe; dN++) {
-    bDrawCircleSingle (xc, yc, radius + dN);
+    bDrawCircleSingle (buffer, xc, yc, radius + dN);
   }
   return;
@@ -284,5 +333,5 @@
 
 // draw a pure circle  
-void bDrawCircleSingle (double xc, double yc, double radius) {
+void bDrawCircleSingle (bDrawBuffer *buffer, double xc, double yc, double radius) {
 
   int Xc, Yc, Radius;
@@ -300,12 +349,12 @@
 
   while (x <= y) {
-    bDrawPoint (Xc+x, Yc+y);
-    bDrawPoint (Xc+x, Yc-y);
-    bDrawPoint (Xc-x, Yc+y);
-    bDrawPoint (Xc-x, Yc-y);
-    bDrawPoint (Xc+y, Yc+x);
-    bDrawPoint (Xc+y, Yc-x);
-    bDrawPoint (Xc-y, Yc+x);
-    bDrawPoint (Xc-y, Yc-x);
+    bDrawPoint (buffer, Xc+x, Yc+y);
+    bDrawPoint (buffer, Xc+x, Yc-y);
+    bDrawPoint (buffer, Xc-x, Yc+y);
+    bDrawPoint (buffer, Xc-x, Yc-y);
+    bDrawPoint (buffer, Xc+y, Yc+x);
+    bDrawPoint (buffer, Xc+y, Yc-x);
+    bDrawPoint (buffer, Xc-y, Yc+x);
+    bDrawPoint (buffer, Xc-y, Yc-x);
 
     if (d < 0) {
@@ -322,5 +371,5 @@
 
 // draw a pure circle  
-void bDrawCircleFill (double xc, double yc, double radius) {
+void bDrawCircleFill (bDrawBuffer *buffer, double xc, double yc, double radius) {
 
   int Xc, Yc, Radius;
@@ -338,8 +387,8 @@
 
   while (x <= y) {
-    bDrawLineHorizontal (Xc-x, Xc+x, Yc+y);
-    bDrawLineHorizontal (Xc-x, Xc+x, Yc-y);
-    bDrawLineHorizontal (Xc-y, Xc+y, Yc+x);
-    bDrawLineHorizontal (Xc-y, Xc+y, Yc-x);
+    bDrawLineHorizontal (buffer, Xc-x, Xc+x, Yc+y);
+    bDrawLineHorizontal (buffer, Xc-x, Xc+x, Yc-y);
+    bDrawLineHorizontal (buffer, Xc-y, Xc+y, Yc+x);
+    bDrawLineHorizontal (buffer, Xc-y, Xc+y, Yc-x);
 
     if (d < 0) {
Index: /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawRotFont.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawRotFont.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/libkapa/src/bDrawRotFont.c	(revision 30118)
@@ -6,8 +6,9 @@
 # define NEARINT(x) ((x < 0) ? ((int)(x - 0.5)) : ((int)(x + 0.5)))
   
-static bDrawColor black;
-static bDrawColor white;
-
-int bDrawRotText (int x, int y, char *string, int pos, double angle) {
+// XXX need to pass the rot text color here
+// static bDrawColor black;
+// static bDrawColor white;
+
+int bDrawRotText (bDrawBuffer *buffer, int x, int y, char *string, int pos, double angle) {
 
   unsigned char *bitmap;
@@ -19,6 +20,6 @@
   RotFont *currentfont;
 
-  white = KapaColorByName ("white");
-  black = KapaColorByName ("black");
+  // white = KapaColorByName ("white");
+  // black = KapaColorByName ("black");
 
   currentname = GetRotFont (&currentsize);
@@ -111,5 +112,5 @@
     X = x + (int)(Xoff*cs - Yoff*sn) + (int)(currentscale*currentfont[N].ascent*sn);
     Y = y + (int)(Xoff*sn + Yoff*cs) - (int)(currentscale*currentfont[N].ascent*cs);
-    bDrawRotBitmap (X, Y, dx, dy, bitmap, TRUE, angle, currentscale);
+    bDrawRotBitmap (buffer, X, Y, dx, dy, bitmap, TRUE, angle, currentscale);
     Xoff += 1 + (int)(currentscale*dx + 0.5);
   }
@@ -118,17 +119,16 @@
 }
 
-int bDrawRotBitmap (int x, int y, int dx, int dy, unsigned char *bitmap, int mode, double angle, double scale) {
+int bDrawRotBitmap (bDrawBuffer *buffer, int x, int y, int dx, int dy, unsigned char *bitmap, int mode, double angle, double scale) {
 
   int ii, jj, byte_line, byte, bit, flag;
-  bDrawColor color;
   double i, j, cs, sn, rscale, tmp;
   int X, Y, X0, X1, X2, Y0, Y1, Y2, x0, y0;
 
   /* this mode option is nort actually used... */
-  if (mode) {
-    color = black;
-  } else {
-    color = white;
-  } 
+  // if (mode) {
+  //   color = black;
+  // } else {
+  //   color = white;
+  // } 
     
   byte_line = (int) ((dx + 7) / 8);
@@ -148,5 +148,5 @@
   Y = YPROC (dx,0);
 # ifdef DRAWBOXES
-  bDrawLine (x+X, y+Y, x+X1, y+Y1);
+  bDrawLine (buffer, x+X, y+Y, x+X1, y+Y1);
   Xt = X;
   Yt = Y;
@@ -160,5 +160,5 @@
   Y = YPROC (dx,dy);
 # ifdef DRAWBOXES
-  bDrawLine (x+X, y+Y, x+Xt, y+Yt);
+  bDrawLine (buffer, x+X, y+Y, x+Xt, y+Yt);
   Xt = X;
   Yt = Y;
@@ -172,5 +172,5 @@
   Y = YPROC (0,dy);
 # ifdef DRAWBOXES
-  bDrawLine (x+X, y+Y, x+Xt, y+Yt);
+  bDrawLine (buffer, x+X, y+Y, x+Xt, y+Yt);
   Xt = X;
   Yt = Y;
@@ -181,5 +181,5 @@
   X2 = MAX (X, X2);
 
-  bDrawSetStyle (color, 0, 0);
+  // bDrawSetStyle (color, 0, 0);
   if (scale > 1) {
     for (i = X1; i <= X2; i+=1) {
@@ -191,5 +191,5 @@
 	bit = ii % 8;
 	flag = 0x01 & (bitmap[byte] >> bit);
-	if (flag) bDrawPointf (x + i, y + j);
+	if (flag) bDrawPointf (buffer, x + i, y + j);
       }
     }
@@ -203,9 +203,9 @@
 	bit = ii % 8;
 	flag = 0x01 & (bitmap[byte] >> bit);
-	if (flag) bDrawPointf (x + i, y + j);
+	if (flag) bDrawPointf (buffer, x + i, y + j);
       }
     }
   }
-  bDrawSetStyle (black, 0, 0);
+  // bDrawSetStyle (black, 0, 0);
   return (TRUE);
 }
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.astro/region.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.astro/region.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.astro/region.c	(revision 30118)
@@ -55,4 +55,5 @@
   if ((argc != 4) && (argc != 5)) {
     gprint (GP_ERR, "USAGE: region Ra Dec Radius [projection] [orientation]\n");
+    gprint (GP_ERR, "  [-image] [-ew] [+ew] [-ns] [+ns] [-no-clear]\n");
     gprint (GP_ERR, " current: %f %f (%f x %f) (%s)\n", 
 	     graphmode.coords.crval1, graphmode.coords.crval2, 
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/Makefile	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/Makefile	(revision 30118)
@@ -36,4 +36,5 @@
 $(SRC)/cut.$(ARCH).o		\
 $(SRC)/delete.$(ARCH).o	\
+$(SRC)/densify.$(ARCH).o	\
 $(SRC)/device.$(ARCH).o	\
 $(SRC)/dimendown.$(ARCH).o	\
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/densify.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/densify.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/densify.c	(revision 30118)
@@ -0,0 +1,61 @@
+# include "data.h"
+
+int densify (int argc, char **argv) {
+
+  int i, Nx, Ny, Xb, Yb, Normalize, N;
+  float Xmin, Xmax, dX, Ymin, Ymax, dY;
+  float *val;
+  Buffer *bf;
+  Vector *vx, *vy;
+  opihi_flt *x, *y;
+
+  Normalize = TRUE;
+  if ((N = get_argument (argc, argv, "-raw"))) {
+    remove_argument (N, &argc, argv);
+    Normalize = FALSE;
+  }
+
+  if (argc != 10) {
+    gprint (GP_ERR, "USAGE: densify buffer x y Xmin Xmax dX Ymin Ymax dY\n");
+    return (FALSE);
+  }
+  
+  if ((bf = SelectBuffer (argv[1], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((vx = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((vy = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if (vx[0].Nelements != vy[0].Nelements) return (FALSE);
+
+  REQUIRE_VECTOR_FLT (vx, FALSE); 
+  REQUIRE_VECTOR_FLT (vy, FALSE); 
+
+  Xmin = atof (argv[4]);
+  Xmax = atof (argv[5]);
+  dX   = atof (argv[6]);
+
+  Ymin = atof (argv[7]);
+  Ymax = atof (argv[8]);
+  dY   = atof (argv[9]);
+
+  Nx = (Xmax - Xmin) / dX + 1;
+  Ny = (Ymax - Ymin) / dY + 1;
+  
+  gfits_free_matrix (&bf[0].matrix);
+  gfits_free_header (&bf[0].header);
+  CreateBuffer (bf, Nx, Ny, -32, 0.0, 1.0);
+  strcpy (bf[0].file, "(empty)");
+
+  x = vx[0].elements.Flt;
+  y = vy[0].elements.Flt;
+  val = (float *)bf[0].matrix.buffer;
+  for (i = 0; i < vx[0].Nelements; i++, x++, y++) {
+    Xb = (*x - Xmin) / dX;
+    Yb = (*y - Ymin) / dY;
+    if (Xb >= Nx) continue;
+    if (Yb >= Ny) continue;
+    if (Xb < 0) continue;
+    if (Yb < 0) continue;
+    val[Xb + Yb*Nx] ++;
+  }
+  return (TRUE);
+}
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/init.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/init.c	(revision 30118)
@@ -25,4 +25,5 @@
 int dbselect         PROTO((int, char **));
 int delete           PROTO((int, char **));
+int densify          PROTO((int, char **));
 int device           PROTO((int, char **));
 int dimendown        PROTO((int, char **));
@@ -161,4 +162,5 @@
   {1, "dbselect",     dbselect,         "extract vectors from mysql database table"},
   {1, "delete",       delete,           "delete vectors or images"},
+  {1, "densify",      densify,          "create an image histogram from a set of vectors"},
   {1, "device",       device,           "set / get current graphics device"},
   {1, "dimendown",    dimendown,        "convert image to vector"},
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/rd.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/rd.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/rd.c	(revision 30118)
@@ -184,5 +184,5 @@
     ftable.header[0].buffer = NULL;
     gfits_copy_header (&buf[0].header, ftable.header);
-    status = gfits_fread_ftable_data (f, &ftable);  // this just reads the bytes (not even a SWAP)
+    status = gfits_fread_ftable_data (f, &ftable, FALSE);  // this just reads the bytes (not even a SWAP)
     status = gfits_uncompress_image (&buf[0].header, &buf[0].matrix, &ftable);
     // uncompressing the image leaves the format as an extension
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 30118)
@@ -160,5 +160,5 @@
 
   off_t Nbytes;
-  int i, j, k, N, Nextend, Ny, Binary, vecType;
+  int i, j, k, N, Nextend, Ny, Binary, vecType, padIfShort;
   char type[16], ID[80], *CCDKeyword;
   FTable table;
@@ -174,4 +174,10 @@
     CCDKeyword = strcreate (argv[N]);
     remove_argument (N, &argc, argv);
+  }
+
+  padIfShort = FALSE;
+  if ((N = get_argument (argc, argv, "-pad-if-short"))) {
+    remove_argument (N, &argc, argv);
+    padIfShort = TRUE;
   }
 
@@ -205,5 +211,5 @@
     }
     if (!gfits_load_header (f, &header)) ESCAPE ("error reading header for extension");
-    if (!gfits_fread_ftable_data (f, &table)) ESCAPE ("error reading table for extension");
+    if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension");
 
   } else {
@@ -236,5 +242,5 @@
 	continue;
       }
-      if (!gfits_fread_ftable_data (f, &table)) ESCAPE ("error reading table for extension");
+      if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension");
       break;
     }
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/resize.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/resize.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/resize.c	(revision 30118)
@@ -17,4 +17,10 @@
   if (!GetImage (NULL, &kapa, name)) return (FALSE);
   FREE (name);
+
+  if ((N = get_argument (argc, argv, "-by-image"))) {
+    remove_argument (N, &argc, argv);
+    KiiResizeByImage (kapa);
+    return (TRUE);
+  }
 
   if (argc != 3) {
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/section.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/section.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/section.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "data.h"
 
-enum {NONE, LIST, UP, DOWN, TOP, BOTTOM, TOOL, BG};
+enum {NONE, LIST, UP, DOWN, TOP, BOTTOM, TOOL, BG, IMAGE};
 
 int section (int argc, char **argv) {
@@ -49,4 +49,9 @@
     remove_argument (N, &argc, argv);
     action = BG;
+  }
+
+  if ((N = get_argument (argc, argv, "-image"))) {
+    remove_argument (N, &argc, argv);
+    action = IMAGE;
   }
 
@@ -130,4 +135,14 @@
   } 
   
+  if (argc == 4) {
+    /* set section */
+    section.name = argv[1];
+    section.x = atof (argv[2]);
+    section.y = atof (argv[3]);
+    section.bg = background;
+    KapaSetSectionByImage (kapa, &section);
+    return (TRUE);
+  }
+
   if (argc == 6) {
     /* set section */
@@ -142,4 +157,5 @@
   }
   gprint (GP_ERR, "USAGE: section name [x y dx dy]\n");
+  gprint (GP_ERR, "USAGE: section name [-image x y] : width based on current image\n");
   gprint (GP_ERR, "USAGE: section name [-list] [-up] [-down] [-top] [-bottom]\n");
   return (FALSE);
Index: /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/vgauss.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/vgauss.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/cmd.data/vgauss.c	(revision 30118)
@@ -45,4 +45,6 @@
   CastVector (yvec, OPIHI_FLT);
   CastVector (svec, OPIHI_FLT);
+  // XXX Cast is failing.
+    
 
   Npts = xvec[0].Nelements;
Index: /branches/czw_branch/20101203/Ohana/src/opihi/dvo/images.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/dvo/images.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/dvo/images.c	(revision 30118)
@@ -11,9 +11,9 @@
 int images (int argc, char **argv) {
 
-  off_t i, Nimage;
+  off_t i, Nimage, Nmosaic;
   int j, status, InPic, leftside, *plist, TimeSelect, ByName;
   int WITH_MOSAIC, SOLO_MOSAIC, HIDDEN;
   time_t tzero, tend;
-  int N, NPTS, n, npts, Npts, kapa;
+  int N, NPTS, n, npts, Npts, kapa, *foundMosaic;
   Vector Xvec, Yvec;
   double r[8], d[8], x[8], y[8], Rmin, Rmax, Rmid, trange, Radius;
@@ -35,4 +35,5 @@
 
   SOLO_MOSAIC = FALSE;
+  foundMosaic = NULL;
   if ((N = get_argument (argc, argv, "-mosaic"))) {
     remove_argument (N, &argc, argv);
@@ -132,4 +133,9 @@
   BuildChipMatch (image, Nimage);
 
+  if (SOLO_MOSAIC && photcode) {
+    ALLOCATE(foundMosaic, int, Nimage);
+    memset(foundMosaic, 0, Nimage*sizeof(int));
+  }
+
   Rmin = graphmode.coords.crval1 - 180.0;
   Rmax = graphmode.coords.crval1 + 180.0;
@@ -137,4 +143,5 @@
   
   int DistortImage = wordhash ("-DIS");
+  int ChipImage    = wordhash ("-WRP");
   int TriangleUp   = wordhash ("TRP-");
   int TriangleDn   = wordhash ("TRM-");
@@ -150,5 +157,6 @@
     if (ByName && strncmp (image[i].name, name, strlen(name))) continue;
     if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
-    if (!FindMosaicForImage (image, Nimage, i)) continue;
+    if (!(Nmosaic = FindMosaicForImage (image, Nimage, i))) continue;
+    Nmosaic --; // XXX kind of a hack: FindMosaicForImage returns 0 or the mosaic seq number + 1
     if (photcode) {
       if ( photcodeEquiv && (photcode[0].code != GetPhotcodeEquivCodebyCode(image[i].photcode))) continue;
@@ -161,4 +169,31 @@
 
     typehash = wordhash (&image[i].coords.ctype[4]);
+
+    if (photcode && SOLO_MOSAIC) {
+      // mosaic (DIS) images are not currently given a photcode : plot these via the WRP entries
+      /* DIS images represent a field, not a chip */
+      if (typehash != ChipImage) continue;
+      if (foundMosaic[Nmosaic]) continue;
+      x[0] = -0.5*image[Nmosaic].NX; y[0] = -0.5*image[Nmosaic].NY;
+      x[1] = +0.5*image[Nmosaic].NX; y[1] = -0.5*image[Nmosaic].NY;
+      x[2] = +0.5*image[Nmosaic].NX; y[2] = +0.5*image[Nmosaic].NY;
+      x[3] = -0.5*image[Nmosaic].NX; y[3] = +0.5*image[Nmosaic].NY;
+      for (j = 0; j < Npts; j++) {
+	status = XY_to_RD (&r[j], &d[j], x[j], y[j], &image[Nmosaic].coords);
+	if (!status) break;
+	r[j] = ohana_normalize_angle (r[j]);
+	while (r[j] < Rmin) { r[j] += 360.0; }
+	while (r[j] > Rmax) { r[j] -= 360.0; }
+	if (j == 0) {
+	  leftside = (r[j] < Rmid);
+	} 
+	if (j > 0) { 
+	  if ( leftside && (r[j] > Rmid + 90)) { r[j] -= 360.0; }
+	  if (!leftside && (r[j] < Rmid - 90)) { r[j] += 360.0; }
+	}
+      }
+      foundMosaic[Nmosaic] = TRUE;
+      goto plot_points;
+    }
 
     /* DIS images represent a field, not a chip */
@@ -270,4 +305,6 @@
     if (Npts == 0) continue;
 
+  plot_points:
+
     status = FALSE;
     for (j = 0; j < Npts; j++) {
@@ -320,4 +357,5 @@
   free (Yvec.elements.Flt);
   FreeImages (image);
+  FREE (foundMosaic);
   return (TRUE);
 
Index: /branches/czw_branch/20101203/Ohana/src/opihi/dvo/imlist.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/dvo/imlist.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/dvo/imlist.c	(revision 30118)
@@ -104,6 +104,6 @@
       XY_to_RD (&r, &d, 0.5*image[i].NX, 0.5*image[i].NY, &image[i].coords);
     }
-    gprint (GP_LOG, "%3lld %s %8.4f %8.4f %f %5d %2d %4.2f %5.3f %5.3f\n", 
-	    (long long) i, image[i].name, r, d, t, image[i].nstar, image[i].photcode, image[i].secz, image[i].Mcal, image[i].dMcal);
+    gprint (GP_LOG, "%3lld %s %8lld %8.4f %8.4f %f %5d %2d %4.2f %5.3f %5.3f\n", 
+	    (long long) i, image[i].name, (long long) image[i].imageID, r, d, t, image[i].nstar, image[i].photcode, image[i].secz, image[i].Mcal, image[i].dMcal);
   }
 
Index: /branches/czw_branch/20101203/Ohana/src/opihi/lib.data/starfuncs.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/opihi/lib.data/starfuncs.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/opihi/lib.data/starfuncs.c	(revision 30118)
@@ -5,5 +5,5 @@
   double *ring;
   double x, y, x2, y2, xy, I, sky, FWHMx, FWHMy, value, mag, Sxy;
-  int i, j, n, Npix2, Nring, Nmax;
+  int i, j, n, Radius, Nring, Nmax;
   double Npts, gain, dsky2, dmag, peak, offset;
   char *string;
@@ -19,6 +19,6 @@
   Nborder = MIN (1000, Nborder);
   
-  Npix2 = (int)(0.5*Npix);
-  Npix = 2 * Npix2 + 1;
+  Radius = (int)(0.5*Npix);
+  Npix = 2 * Radius + 1;
   Nring = 4*Nborder*(Nborder + Npix);
   ALLOCATE (ring, double, Nring);
@@ -27,11 +27,11 @@
   n = 0;  
   for (j = 0; j < Nborder; j++) {
-    for (i = X - Npix2 - Nborder; i < X + Npix2 + Nborder + 1; i++, n+=2) {
-      ring[n]   = gfits_get_matrix_value (matrix, i, (int)(Y - Npix2 - j));
-      ring[n+1] = gfits_get_matrix_value (matrix, i, (int)(Y + Npix2 + j));
-    }
-    for (i = Y - Npix2; i < Y + Npix2 + 1; i++, n+=2) {
-      ring[n]   = gfits_get_matrix_value (matrix, (int)(X - Npix2 - j), i);
-      ring[n+1] = gfits_get_matrix_value (matrix, (int)(X + Npix2 + j), i);
+    for (i = X - Radius - Nborder; i < X + Radius + Nborder + 1; i++, n+=2) {
+      ring[n]   = gfits_get_matrix_value (matrix, i, (int)(Y - Radius - j));
+      ring[n+1] = gfits_get_matrix_value (matrix, i, (int)(Y + Radius + j));
+    }
+    for (i = Y - Radius; i < Y + Radius + 1; i++, n+=2) {
+      ring[n]   = gfits_get_matrix_value (matrix, (int)(X - Radius - j), i);
+      ring[n+1] = gfits_get_matrix_value (matrix, (int)(X + Radius + j), i);
     }
   }
@@ -50,6 +50,7 @@
   Npts = Nmax = 0;
   x = y = x2 = y2 = xy = I = 0;
-  for (i = X - Npix2; i < X + Npix2 + 1; i++) {
-    for (j = Y - Npix2; j < Y + Npix2 + 1; j++) {
+  for (i = X - Radius; i < X + Radius + 1; i++) {
+    for (j = Y - Radius; j < Y + Radius + 1; j++) {
+      if (hypot((i-X), (j-Y)) > Radius) continue;
       value = gfits_get_matrix_value (matrix, i, j);
       offset = value - sky;
@@ -92,4 +93,5 @@
   set_variable ("Zpk", peak);
   set_int_variable ("Nsat", Nmax);
+  set_int_variable ("Npts", Npts);
   
   gprint (GP_LOG, "%f %f %f %f %f %f %f %f\n", x, y, FWHMx, FWHMy, sky, I, mag, dmag);
Index: /branches/czw_branch/20101203/Ohana/src/photdbc/include/photdbc.h
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/photdbc/include/photdbc.h	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/photdbc/include/photdbc.h	(revision 30118)
@@ -114,2 +114,3 @@
 int SetSignals (void);
 int copy_images (char *outdir);
+void usage();
Index: /branches/czw_branch/20101203/Ohana/src/photdbc/src/args.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/photdbc/src/args.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/photdbc/src/args.c	(revision 30118)
@@ -61,8 +61,5 @@
   }
 
-  if (argc != 2) {
-    fprintf (stderr, "USAGE: photdbc (output)\n");
-    exit (2);
-  } 
+  if (argc != 2) usage();
 
   if ((REGION.Rmin == 0) && (REGION.Rmax == 360) && (REGION.Dmin == -90) && (REGION.Dmax == +90)) {
@@ -80,23 +77,24 @@
 }
 
-/**
+void usage() {
 
- this program takes an existing DVO database and makes a copy, applying a number of optional
- filters in the process.  
-
- photdbc (output)
-
- allowed filters / restrictions include:
-
- -region ra dec ra dec : limit operation to the specified region 
- -join                 : join measurements between stars using JOIN_RADIUS
- -ccdregion X Y X Y    : only keep detections within the specified detector region
-                         (can this be limited to specific photcodes? cameras? detectors?)
- -photcode_limits code Mmin Mmax : allow multiples of these
-
- SIGMA_MAX
- NMEAS_MIN
- INST_MAG_MAX
- INST_MAG_MIN
-
-**/
+  fprintf (stderr, "USAGE: photdbc (output)\n\n");
+  fprintf (stderr, " this program takes an existing DVO database and makes a copy, applying a number of optional\n");
+  fprintf (stderr, " filters in the process.  \n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, " photdbc (output)\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, " allowed filters / restrictions include:\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, " -region Rmin Rmax Dmin Dmax : limit operation to the specified region \n");
+  fprintf (stderr, " -join                 : join measurements between stars using JOIN_RADIUS\n");
+  fprintf (stderr, " -ccdregion X Y X Y    : only keep detections within the specified detector region\n");
+  fprintf (stderr, "                         (can this be limited to specific photcodes? cameras? detectors?)\n");
+  fprintf (stderr, " -photcode_limits code Mmin Mmax : allow multiples of these\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, " SIGMA_MAX\n");
+  fprintf (stderr, " NMEAS_MIN\n");
+  fprintf (stderr, " INST_MAG_MAX\n");
+  fprintf (stderr, " INST_MAG_MIN\n");
+  exit (2);
+}
Index: /branches/czw_branch/20101203/Ohana/src/photdbc/src/initialize.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/photdbc/src/initialize.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/photdbc/src/initialize.c	(revision 30118)
@@ -4,4 +4,9 @@
 
   /* are these set correctly? */
+  if (get_argument (argc, argv, "-h")) usage();
+  if (get_argument (argc, argv, "--h")) usage();
+  if (get_argument (argc, argv, "-help")) usage();
+  if (get_argument (argc, argv, "--help")) usage();
+
   ConfigInit (&argc, argv);
   args (argc, argv);
Index: /branches/czw_branch/20101203/Ohana/src/photdbc/src/join_stars.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/photdbc/src/join_stars.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/photdbc/src/join_stars.c	(revision 30118)
@@ -32,4 +32,5 @@
 
   /* reference for coords is this region */
+  Ncurr = 0;
   Naves = 0;
   Rmid = Dmid = 0;
Index: /branches/czw_branch/20101203/Ohana/src/relastro/src/GetAstromError.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/relastro/src/GetAstromError.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/relastro/src/GetAstromError.c	(revision 30118)
@@ -2,8 +2,8 @@
 
 float GetAstromError (Measure *measure, int mode) {
-
+  //BIG HACKXXXXXXXX
+  return 0.1;
   PhotCode *code;
   float dPobs, dPsys, dPtotal, dM, AS, MS;
-
   switch (mode) {
     case ERROR_MODE_RA:
@@ -19,5 +19,4 @@
       abort();
   }
-
   /* the astrometric errors are not being carried yet (but should be!) */
   /* we use the photometric mag error as a weighting term */
@@ -28,5 +27,4 @@
   dPsys = code[0].astromErrSys;
   dM    = measure[0].dM;
-  
   dPtotal = sqrt(SQ(dPsys) + AS*SQ(dPobs) + MS*SQ(dM));
 
@@ -35,5 +33,4 @@
 
   dPtotal = MAX (dPtotal, MIN_ERROR);
-
   return (dPtotal);
 }
Index: /branches/czw_branch/20101203/Ohana/src/relastro/src/UpdateObjects.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/relastro/src/UpdateObjects.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/relastro/src/UpdateObjects.c	(revision 30118)
@@ -54,5 +54,4 @@
   memset (&fitPM,  0, sizeof(fitPM));
   memset (&fitPAR, 0, sizeof(fitPAR));
-  
   initObjectData (catalog, Ncatalog);
 
@@ -72,5 +71,4 @@
   // use J2000 as a reference time
   T2000 = ohana_date_to_sec ("2000/01/01");
-
   // XXX in the future, use catalog[0].Nsecfilt only?  allow catalogs to have variable Nsecfilt?
   Nsecfilt = GetPhotcodeNsecfilt ();
@@ -97,5 +95,4 @@
       N = 0;
       m = catalog[i].average[j].measureOffset;
-
       Tmin = Tmax = (catalog[i].measure[m].t - T2000) / (86400*365.25);
       mode = FIT_MODE;
@@ -137,6 +134,9 @@
 
 	// dX, dY : error in arcsec -- 
-	dX[N] = GetAstromError (&catalog[i].measure[m], ERROR_MODE_RA);
-	dY[N] = GetAstromError (&catalog[i].measure[m], ERROR_MODE_DEC);
+	// dX[N] = GetAstromError (&catalog[i].measure[m], ERROR_MODE_RA);
+	// dY[N] = GetAstromError (&catalog[i].measure[m], ERROR_MODE_DEC);
+
+	dX[N] = 0.1;
+	dY[N] = 0.1;
 	dT[N] = catalog[i].measure[m].dt;
 
@@ -145,6 +145,6 @@
 	// non-circular errors (different values for X and Y), then dR and dD will be
 	// incorrect: they would need to be rotated to take out the position angle
-	dR[k] = dX[k] / 3600.0;
-	dD[k] = dY[k] / 3600.0;
+	dR[N] = dX[N] / 3600.0;
+	dD[N] = dY[N] / 3600.0;
 
 	N++;
@@ -194,4 +194,5 @@
 
 	FitPM (&fitPM, X, dX, Y, dY, T, N);
+
 	if (XVERB) fprintf (stderr, "fitted:  %f - %f : %f %f : %f %f : %f vs %f\n", Tmin, Tmax, fitPM.Ro, fitPM.Do, fitPM.uR, fitPM.uD, fitPM.chisq, fitAve.chisq);
 
@@ -244,27 +245,29 @@
 
       switch (result) {
-	case FIT_AVERAGE:
-	  catalog[i].average[j].flags |= ID_STAR_USE_AVE;
-	  fit = fitAve;
-	  break;
-	case FIT_PM_ONLY:
-	  catalog[i].average[j].flags |= ID_STAR_USE_PM;
-	  fit = fitPM;
-	  break;
-	case FIT_PM_AND_PAR:
-	  catalog[i].average[j].flags |= ID_STAR_USE_PAR;
-	  fit = fitPAR;
-	  break;
-      }
-
-      if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f)\n",
+      case FIT_AVERAGE:
+	catalog[i].average[j].flags |= ID_STAR_USE_AVE;
+	fit = fitAve;
+	break;
+      case FIT_PM_ONLY:
+	catalog[i].average[j].flags |= ID_STAR_USE_PM;
+	fit = fitPM;
+	break;
+      case FIT_PM_AND_PAR:
+	catalog[i].average[j].flags |= ID_STAR_USE_PAR;
+	fit = fitPAR;
+	break;
+      }
+      if (XVERB) fprintf (stderr, "A%f %f -> %f %f (%f,%f) pm=(%f %f)\n",
 			  catalog[i].average[j].R, 
 			  catalog[i].average[j].D, 
 			  fit.Ro, fit.Do, 
 			  3600*(catalog[i].average[j].R - fit.Ro), 
-			  3600*(catalog[i].average[j].D - fit.Do));
+			  3600*(catalog[i].average[j].D - fit.Do),
+			  fit.uR,
+			  fit.uD);
 
       //make sure that the fit succeeded
-      status  = finite(fit.Ro);
+      status = TRUE;
+      status &= finite(fit.Ro);
       status &= finite(fit.Do);
       status &= finite(fit.dRo);
@@ -310,4 +313,13 @@
       catalog[i].average[j].Trange = (Trange * 86400 * 365.26);
       catalog[i].average[j].Npos = fit.Nfit;
+      if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f) pm=(%f %f)\n",
+                          catalog[i].average[j].R,
+                          catalog[i].average[j].D,
+                          fit.Ro, fit.Do,
+                          3600*(catalog[i].average[j].R - fit.Ro),
+                          3600*(catalog[i].average[j].D - fit.Do),
+                          catalog[i].average[j].uR,
+                          catalog[i].average[j].uD);
+
     }
 
Index: /branches/czw_branch/20101203/Ohana/src/relastro/src/high_speed_objects.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/relastro/src/high_speed_objects.c	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/relastro/src/high_speed_objects.c	(revision 30118)
@@ -13,13 +13,46 @@
   // XXX seems silly to require region here just to find the catalog bounds / center
 
-  off_t i, j, m, J, ni, nj, *N1, Nslow, Ninvalid, NgroupA, NgroupB, NgroupAbad, NgroupBbad;
-  int *slowMoving, *groupA, *groupB, status, foundA, foundB, Nmatch, valid;
+  off_t i, j, m, J, ni, nj, *N1, Nslow, Ninvalid, NgroupA, NgroupB, NgroupAbad, NgroupBbad,l,i1,Noff,Nmeasure,Naverage, NAVERAGE, NMEASURE;
+  int *slowMoving, *groupA, *groupB, status, foundA, foundB, Nmatch, valid,Nmatchmeas,Nepoch,nv[2],Nmatchmeasobj;
   double *X1, *Y1;
-  double dX, dY, dR, RADIUS2, yJ;
+  double dX, dY, dR, RADIUS2;
   Coords tcoords;
+  Catalog catalog1;
 
   int zcode, zNsec, ycode, yNsec, jcode, jNsec, hcode, hNsec, kcode, kNsec, USNO_R, USNO_N, Nsecfilt;
+  char filename[1024];
+  char outdir[]="/data/ipp022.0/ndeacon/hispeedzy";
+  Noff = strlen(CATDIR);
+  sprintf (filename, "%s/%s", outdir, &catalog[0].filename[Noff]);
+  dvo_catalog_init(&catalog1, TRUE); /*initialise new catalogue*/
+  catalog1.filename = strcreate(filename);
+
+  SIGMA_LIM = 0.0;
 
   Nsecfilt = GetPhotcodeNsecfilt();
+  Naverage=catalog[0].Naverage;
+  Nmeasure=catalog[0].Nmeasure;
+  // ALLOCATE (catalog1.average, Average,Naverage);
+  // ALLOCATE (catalog1.measure, Measure,Nmeasure);
+  // ALLOCATE(catalog1.secfilt, SecFilt,catalog[0].Naverage*Nsecfilt);
+  catalog1.filename = filename; // based on the input name, need to keep everything below the catdir portion
+  catalog1.Nsecfilt  = Nsecfilt;
+  // always load all of the data (if any exists)
+  catalog1.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+  
+  catalog1.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+  catalog1.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+
+  if (!dvo_catalog_open (&catalog1, region, VERBOSE,"w")) {
+    fprintf (stderr, "ERROR: failure to open catalog file %s\n",
+	     filename);
+    exit (2);
+  }
+
+  NAVERAGE = 1000;
+  NMEASURE = 10000;
+  REALLOCATE (catalog1.average, Average, NAVERAGE);
+  REALLOCATE (catalog1.measure, Measure, NMEASURE);
+  REALLOCATE(catalog1.secfilt, SecFilt, NAVERAGE*Nsecfilt);
 
   ycode = GetPhotcodeCodebyName("y");
@@ -67,5 +100,5 @@
   NgroupBbad = 0;
 
-  fprintf (stdout, "#      RA_A  DEC_A              RA_B  DEC_B      :     pmx     pmy      dR  :    z      dz       y      dy       J      dJ       H      dH       K      dK\n");
+  fprintf (stdout, "#      RA_A  DEC_A              RA_B  DEC_B      :     pmx     pmy      dR  dt:    z      dz       y      dy       J      dJ       H      dH       K      dK\n");
   //................270.2346670  20.2471540  270.2170434  20.2717396 :  -59.11   88.78   106.66 :   0.000  0.000   19.582  0.112   16.041  0.110   15.388  0.098   14.858  0.001
 
@@ -88,4 +121,9 @@
     foundA = FALSE;
     for (j = 0; !foundA && (j < catalog[0].average[i].Nmeasure); j++, m++) {
+      if((catalog[0].average[i].R>204.1923)&&(catalog[0].average[i].R<204.1924)&&(catalog[0].average[i].D>11.376)&&(catalog[0].average[i].D<11.377))
+	{
+	  printf("Hello");
+	}
+
       if (MeasMatchesPhotcode(&catalog[0].measure[m], photcodesGroupA, NphotcodesGroupA)) {
 	foundA = TRUE;
@@ -97,4 +135,10 @@
     foundB = FALSE;
     for (j = 0; !foundB && (j < catalog[0].average[i].Nmeasure); j++, m++) {
+                                                   
+      if((catalog[0].average[i].R>204.192)&&(catalog[0].average[i].R<204.1925)&&(catalog[0].average[i].D>11.376)&&(catalog[0].average[i].D<11.377))
+        {
+          printf("Hello");
+        }
+
       if (MeasMatchesPhotcode(&catalog[0].measure[m], photcodesGroupB, NphotcodesGroupB)) {
 	foundB = TRUE;
@@ -114,13 +158,19 @@
     if (foundA && !foundB) {
       // average-based tests:
+                                                   
+      if((catalog[0].average[i].R>204.1923)&&(catalog[0].average[i].R<204.1924)&&(catalog[0].average[i].D>11.376)&&(catalog[0].average[i].D<11.377))
+	{
+          printf("Hello");
+        }
+
       valid = TRUE;
-      valid &= ((catalog[0].average[i].flags & 0x40000) == 0);
-      valid &= ((catalog[0].average[i].flags & 0x80000)  > 0);
-      valid &= (catalog[0].secfilt[i*Nsecfilt + yNsec].M < 1.0);
-      valid &= (catalog[0].secfilt[i*Nsecfilt + zNsec].M < 1.0);
+      valid &= ((catalog[0].average[i].flags & 0x02000000) == 0);
+      valid &= ((catalog[0].average[i].flags & 0x08000000)  > 0);
+      valid &= ((catalog[0].secfilt[i*Nsecfilt + yNsec].M < 1.0)||(isnan(catalog[0].secfilt[i*Nsecfilt + yNsec].M)));
+      valid &= (((catalog[0].secfilt[i*Nsecfilt + zNsec].M < 1.0))||(isnan(catalog[0].secfilt[i*Nsecfilt + zNsec].M)));
       // XXX color restrictions are applied in the pair-wise matching below
       
       // measure-based tests:
-      m = catalog[0].average[i].measureOffset;
+      /*      m = catalog[0].average[i].measureOffset;
       for (j = 0; valid && (j < catalog[0].average[i].Nmeasure); j++, m++) {
 	if (catalog[0].measure[m].photcode == USNO_R) {
@@ -130,5 +180,5 @@
 	  valid &= ((catalog[0].measure[m].M > 18.0) || isnan(catalog[0].measure[m].M));
 	}
-      }
+	}*/
 
       // ((objflags & 524288) == 524288) && 
@@ -154,19 +204,25 @@
 
       // average-based tests:
+      if((catalog[0].average[i].R>204.192)&&(catalog[0].average[i].R<204.193)&&(catalog[0].average[i].D>11.372)&&(catalog[0].average[i].D<11.373))
+	{
+	  printf("Hello");
+	}
       valid = TRUE;
-      valid &= ((catalog[0].average[i].flags & 0x10000) == 0);
-      valid &= ((catalog[0].average[i].flags & 0x20000)  > 0);
-      valid &= (catalog[0].secfilt[i*Nsecfilt + jNsec].M < 1.0);
+      valid &= ((catalog[0].average[i].flags & 0x01000000) == 0);
+
+      valid &= ((catalog[0].average[i].flags & 0x04000000)  > 0);
+
+      valid &= ((catalog[0].secfilt[i*Nsecfilt + jNsec].M < 1.0)||(isnan(catalog[0].secfilt[i*Nsecfilt + jNsec].M)));
       valid &= (catalog[0].secfilt[i*Nsecfilt + yNsec].Nused > 1);
       valid &= (catalog[0].secfilt[i*Nsecfilt + yNsec].dM < 0.2);
 
-      if ((catalog[0].secfilt[i*Nsecfilt + zNsec].M < 1.0) || (catalog[0].secfilt[i*Nsecfilt + zNsec].Nused == 1)) {
+      /*if ((catalog[0].secfilt[i*Nsecfilt + zNsec].M < 1.0) || (catalog[0].secfilt[i*Nsecfilt + zNsec].Nused == 1)) {
 	valid &= TRUE;
       } else {
 	valid &= ((catalog[0].secfilt[i*Nsecfilt + zNsec].M - catalog[0].secfilt[i*Nsecfilt + yNsec].M) > 0.2);
-      }
+	}*/
 
       // measure-based tests:
-      m = catalog[0].average[i].measureOffset;
+      /*m = catalog[0].average[i].measureOffset;
       for (j = 0; valid && (j < catalog[0].average[i].Nmeasure); j++, m++) {
 	if (catalog[0].measure[m].photcode == USNO_R) {
@@ -176,5 +232,5 @@
 	  valid &= ((catalog[0].measure[m].M > 18.5) || isnan(catalog[0].measure[m].M));
 	}
-      }
+	}*/
 
       // (abs(glat)>15.0) && 
@@ -236,4 +292,5 @@
 
   Nmatch = 0;
+  Nmatchmeas = 0;
   RADIUS2 = SQ(RADIUS);
 
@@ -243,5 +300,4 @@
     ni = N1[i];
     nj = N1[j];
-
     // if (ni == 131030) {
     //   fprintf (stderr, "got 2mass\n");
@@ -268,5 +324,5 @@
 
     // within match range; look for valid matches
-    for (J = j; (dX > -1.02*RADIUS) && (J < catalog[0].Naverage); J++) {
+    for (J = j; (dX > -1.02*RADIUS) && (J < catalog[0].Naverage); J++) {     
       if (J == i) continue;  // avoid auto-matches
 
@@ -281,18 +337,53 @@
 
       // y_groupA - J_groupB 
-      yJ = catalog[0].secfilt[nj*Nsecfilt + yNsec].M - catalog[0].secfilt[ni*Nsecfilt + jNsec].M;
+
+      /*      yJ = catalog[0].secfilt[nj*Nsecfilt + yNsec].M - catalog[0].secfilt[ni*Nsecfilt + jNsec].M;
       if (yJ < 1.25) continue;
-      if (yJ > 5.0) continue;
+      if (yJ > 5.0) continue;*/
 
       /*** a match is found (just print it for the moment) ***/
+      /*Define a vector of matched indices and set averages in new catalogue*/
+      Nepoch=2;
+      FIT_MODE = FIT_PM_ONLY;
+/*nv=(int *)malloc(Nepoch*sizeof(int));*/
+      nv[0]=ni; /*THESE SHOULD BE CHANGED FOR MULTIPLE EPOCHS AS SHOULD nv*/
+      nv[1]=nj;
+
+      catalog1.average[Nmatch]=catalog[0].average[nv[0]];
+      /*Loop over index values and set measurements in new catalogue*/
+      Nmatchmeasobj=0;
+      catalog1.average[Nmatch].measureOffset=Nmatchmeas;
+      for(l=0;l<Nepoch;l++) {
+	  m = catalog[0].average[nv[l]].measureOffset;
+	  for(i1=0;i1<catalog[0].average[nv[l]].Nmeasure;i1++) {
+	      catalog1.measure[Nmatchmeas]=catalog[0].measure[m+i1];
+	      /*Set offset RA and Dec wrt correct average value*/
+	      catalog1.measure[Nmatchmeas].dR=catalog[0].measure[m+i1].dR+3600.0*(catalog[0].average[nv[0]].R-catalog[0].average[nv[l]].R);
+	      catalog1.measure[Nmatchmeas].dD=catalog[0].measure[m+i1].dD+3600.0*(catalog[0].average[nv[0]].D-catalog[0].average[nv[l]].D);
+	      catalog1.measure[Nmatchmeas].averef = Nmatch;
+	      Nmatchmeasobj++;
+	      Nmatchmeas++;
+
+	      if (Nmatchmeas == NMEASURE - 1) {
+		NMEASURE += 10000;
+		REALLOCATE (catalog1.measure, Measure, NMEASURE);
+	      }
+	  }
+      }
+      catalog1.average[Nmatch].Nmeasure=Nmatchmeasobj;
       Nmatch ++;
 
+      if (Nmatch == NAVERAGE - 1) {
+	NAVERAGE += 1000;
+	REALLOCATE (catalog1.average, Average, NAVERAGE);
+	REALLOCATE(catalog1.secfilt, SecFilt, NAVERAGE*Nsecfilt);
+      }
       // for the moment, just write the matches to stdout:
-      float pmx = -dX; // proper-motion displacement in ra  direction (B - A) [arcsec]
-      float pmy = -dY; // proper-motion displacement in dec direction (B - A) [arcsec]
-      fprintf (stdout, "%11.7f %11.7f  %11.7f %11.7f : %7.2f %7.2f  %7.2f : %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f\n", 
+      //float pmx = -dX; // proper-motion displacement in ra  direction (B - A) [arcsec]
+      //float pmy = -dY; // proper-motion displacement in dec direction (B - A) [arcsec]
+      /*           fprintf (stdout, "%11.7f %11.7f  %11.7f %11.7f : %7.2f %7.2f  %7.2f: %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f  %7.3f %6.3f\n", 
 	       catalog[0].average[ni].R, catalog[0].average[ni].D,
 	       catalog[0].average[nj].R, catalog[0].average[nj].D,
-	       pmx, pmy, sqrt(dR),
+	       dX, dY, sqrt(dR),
 	       catalog[0].secfilt[nj*Nsecfilt + zNsec].M,
 	       catalog[0].secfilt[nj*Nsecfilt + zNsec].dM,
@@ -304,10 +395,19 @@
 	       catalog[0].secfilt[ni*Nsecfilt + hNsec].dM,
 	       catalog[0].secfilt[ni*Nsecfilt + kNsec].M,
-	       catalog[0].secfilt[ni*Nsecfilt + kNsec].dM);
+	       catalog[0].secfilt[ni*Nsecfilt + kNsec].dM);*/
     }
     i++;
   }
+  catalog1.Naverage=Nmatch;
+  catalog1.Nmeasure=Nmatchmeas;
+  catalog1.Nsecfilt=Nsecfilt;
+  catalog1.Nsecf_mem=Nmatch*Nsecfilt;
+
+  UpdateObjects(&catalog1, 1);
+
   fprintf (stderr, "found %d matches\n", Nmatch);
-  
+  dvo_catalog_save (&catalog1, VERBOSE);
+  dvo_catalog_unlock (&catalog1);
+  dvo_catalog_free (&catalog1);
   free (slowMoving);
   free (groupA);
Index: /branches/czw_branch/20101203/Ohana/src/relphot/doc/config.txt
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/relphot/doc/config.txt	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/relphot/doc/config.txt	(revision 30118)
@@ -0,0 +1,28 @@
+
+for choosing the bright (tied-down) stars, these are used:
+
+MAG_LIM                 &MAG_LIM        -- faintest stars used
+SIGMA_LIM               &SIGMA_LIM      -- lowest S/N used (sigma = 1/(S/N))
+STAR_SCATTER            &STAR_SCATTER   -- max scatter for a star to be include in the fits 
+IMAGE_SCATTER           &IMAGE_SCATTER  -- max scatter for an image to be kept in the fit
+IMAGE_OFFSET            &IMAGE_OFFSET   -- max zero point offset of an image to be kept in the fit
+STAR_CHISQ              &STAR_CHISQ   -- max chisq for a star  to be include in the fits 
+STAR_TOOFEW             &STAR_TOOFEW   -- star must have more than this good measurements to be used
+IMAGE_TOOFEW            &IMAGE_TOOFEW   -- image must have more than this good measurements to be used
+IMAGE_GOOD_FRACTION     &IMAGE_GOOD_FRACTION   -- image must have more than this (good measurements/all meas) to be used
+
+
+GSCFILE                 GSCFILE   -- source for database sky table if missing
+CATDIR                  CATDIR   -- catdir
+CATMODE                CATMODE   -- output format for DVO tables (should not be used by relphot?)
+CATFORMAT              CATFORMAT   -- output format for DVO tables (should not be used by relphot?)
+PHOTCODE_FILE          MasterPhotcodeFile   -- source for photcode table if missing
+SKY_DEPTH              SKY_DEPTH)) { SKY_DEPTH = 2; } -- output sky partition depth (default is 2, should not be used by relphot)
+ZERO_PT                &ZERO_POINT   -- reference internal zero point, should not be needed (defined by DB)
+
+CAMERA_CONFIG          CameraConfig   -- source of camera description, used for generating correction grid
+MOSAICNAME             MOSAICNAME   -- name to define relationship between chip and camera 
+GRID_TOOFEW            &GRID_TOOFEW   -- correction grid cell must have more than this stars (or is nan)
+RELPHOT_GRID_X         &RELPHOT_GRID_X  -- number of grid cells per chip (x)
+RELPHOT_GRID_Y         &RELPHOT_GRID_Y  -- number of grid cells per chip (y)
+RELPHOT_GRID_BINNING   &RELPHOT_GRID_BINNING  -- ???
Index: /branches/czw_branch/20101203/Ohana/src/tools/Makefile
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/tools/Makefile	(revision 30117)
+++ /branches/czw_branch/20101203/Ohana/src/tools/Makefile	(revision 30118)
@@ -17,5 +17,5 @@
 PROGRAMS = gconfig fhead ftable fields list_astro glockfile \
 radec mktemp precess csystem fits_insert \
-medianfilter mefhead ckfits
+medianfilter mefhead ckfits roc
 
 all tools: $(PROGRAMS)
Index: /branches/czw_branch/20101203/Ohana/src/tools/src/roc.c
===================================================================
--- /branches/czw_branch/20101203/Ohana/src/tools/src/roc.c	(revision 30118)
+++ /branches/czw_branch/20101203/Ohana/src/tools/src/roc.c	(revision 30118)
@@ -0,0 +1,353 @@
+# include <ohana.h>
+# include <gfitsio.h>
+# include <sys/types.h>
+# include <regex.h>
+
+# define myAssert(LOGIC,MSG) { if (!(LOGIC)) { fprintf (stderr, "%s\n", MSG); abort(); } }
+
+# define ROC_HEADER_SIZE  0x1000
+# define ROC_HEADER_BLOCK 0x1000
+# define ROC_BLOCKSIZE    0x8000
+
+int roc_create (int argc, char **argv);
+int roc_repair (int argc, char **argv);
+int roc_insert (int argc, char **argv);
+int roc_delete (int argc, char **argv);
+int usage (void);
+int print_block (char *header, int *header_size, int *Noff, char *format,...);
+
+int main (int argc, char **argv) {
+
+  if (get_argument (argc, argv, "-h")) usage();
+  if (get_argument (argc, argv, "-help")) usage();
+  if (get_argument (argc, argv, "--help")) usage();
+  if (argc < 3) usage();
+
+  if (!strcasecmp(argv[1], "-create")) roc_create (argc, argv);
+  if (!strcasecmp(argv[1], "-repair")) roc_repair (argc, argv);
+  if (!strcasecmp(argv[1], "-insert")) roc_insert (argc, argv);
+  if (!strcasecmp(argv[1], "-delete")) roc_delete (argc, argv);
+
+  usage();
+  exit (1);
+}
+
+int roc_create (int argc, char **argv) {
+
+  int i, j, n, Ninput, result, Nblocks, header_size, size_off, Noff, Nbytes, Nread;
+  off_t maxSize, *sizes, *bytes_read;
+  char value;
+  char *header;
+  char **inputName, *base;
+  char **inputData;
+  char *outputData;
+  FILE **input, *target;
+  struct stat stats;
+
+  if (argc < 4) usage();
+
+  /* find the md5 sum for each input file (ADD LATER)
+   * find the size of the input files
+   * define the output file size = MAX(sizes)
+   * create the target file header
+   * open & read the input files, write the output
+   */
+
+  // the output file
+  char *targetName = argv[2];
+  Ninput = argc - 3;
+
+  // the input files
+  ALLOCATE (inputName, char *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    inputName[i] = strcreate (argv[i + 3]);
+  }
+
+  // check on the input files (validity & sizes)
+  maxSize = 0;
+  ALLOCATE (sizes, off_t, Ninput);
+  ALLOCATE (bytes_read, off_t, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    result = stat (inputName[i], &stats);
+    if (result) {
+      perror("problem with input file");
+      exit (1);
+    }
+    if (!S_ISREG(stats.st_mode)) {
+      fprintf (stderr, "%s is not a regular file\n", inputName[i]);
+      exit (1);
+    }
+    sizes[i] = stats.st_size;
+    maxSize = MAX(maxSize, sizes[i]);
+    bytes_read[i] = 0;
+  }
+
+  ALLOCATE (input, FILE *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    input[i] = fopen(inputName[i], "r");
+    myAssert (input[i], "failed to open file");
+  }
+
+  Nblocks = maxSize / ROC_BLOCKSIZE;
+  if (maxSize % ROC_BLOCKSIZE) {
+    Nblocks = 1 + (int) (maxSize / ROC_BLOCKSIZE);
+  }
+
+  // create the output header
+  header_size = ROC_HEADER_SIZE;
+  ALLOCATE (header, char, header_size);
+
+  Noff = 0;
+  print_block (header, &header_size, &Noff, "ROC Version %d\n", 0);
+
+  size_off = Noff;
+  print_block (header, &header_size, &Noff, "HEADER SIZE 0x%08x\n", header_size); // this is a dummy: re-write below
+  print_block (header, &header_size, &Noff, "N_FILES %d\n", Ninput);
+  print_block (header, &header_size, &Noff, "N_BLOCKS %d\n", Nblocks);
+
+  // write the header information
+  for (i = 0; i < Ninput; i++) {
+    print_block (header, &header_size, &Noff, "FILE_%03d : %s\n", i, inputName[i]);
+    
+    base = filerootname(inputName[i]);
+    print_block (header, &header_size, &Noff, "BASE_%03d : %s\n", i, base);
+    print_block (header, &header_size, &Noff, "SIZE_%03d : %d\n", i, sizes[i]);
+    print_block (header, &header_size, &Noff, "MD5_%03d -- Not Yet Implemented\n", i);
+  }
+  print_block (header, &header_size, &size_off, "HEADER SIZE 0x%08x", header_size);
+  header[size_off] = '\n'; // kind of a hack: print_block writes a NULL char at the end of the string; replace with <RETURN>
+
+  target = fopen(targetName, "w");
+  myAssert (target, "failed to open output");
+
+  fwrite (header, 1, header_size, target);
+
+  ALLOCATE (inputData, char *, Ninput);
+  ALLOCATE (outputData, char, ROC_BLOCKSIZE);
+  for (i = 0; i < Ninput; i++) {
+    ALLOCATE (inputData[i], char, ROC_BLOCKSIZE);
+  }
+
+  for (n = 0; n < Nblocks; n++) {
+    for (i = 0; i < Ninput; i++) {
+      Nread = MIN (ROC_BLOCKSIZE, sizes[i] - bytes_read[i]);
+      Nbytes = fread (inputData[i], 1, Nread, input[i]);
+      myAssert (Nbytes == Nread, "failed to read data");
+      if (Nread < ROC_BLOCKSIZE) {
+	// if we have reached the end of the file, fill in the rest with NULLs
+	memset (&inputData[i][Nread], 0, ROC_BLOCKSIZE - Nread);
+      }
+      bytes_read[i] += Nread;
+    }
+    
+    for (j = 0; j < ROC_BLOCKSIZE; j++) {
+      value = 0;
+      for (i = 0; i < Ninput; i++) {
+	value = value ^ inputData[i][j];
+      }
+      outputData[j] = value;
+    }
+
+    fwrite (outputData, 1, ROC_BLOCKSIZE, target);
+  }
+
+  exit (0);
+}
+
+int roc_repair (int argc, char **argv) {
+
+  int i, j, n, Ninput, Nblocks, header_size, Nbytes, Nread, Nfile, Nwrite;
+  off_t *sizes, *bytes_read;
+  char value;
+  char *header, *line, *ptr;
+  char **inputName, *targetName, *outputName;
+  char **inputData;
+  char *targetData;
+  char *outputData;
+  FILE **input, *target, *output;
+
+  if (argc < 4) usage();
+
+  /* find the md5 sum for each input file (ADD LATER)
+   * find the size of the input files
+   * define the output file size = MAX(sizes)
+   * create the target file header
+   * open & read the input files, write the output
+   */
+
+  // the output file
+  targetName = argv[2];
+  Nfile = atoi(argv[3]);
+  outputName = argv[4];
+
+  if (Nfile < 0) {
+    fprintf (stderr, "invalid file number %d\n", Nfile);
+    exit (3);
+  }
+
+  target = fopen(targetName, "r");
+  myAssert (target, "failed to open output");
+  
+  ALLOCATE (line, char, 1024);
+
+  scan_line (target, line);
+  myAssert (!strncmp(line, "ROC Version 0", strlen("ROC Verion 0")), "invalid ROC file or format");
+
+  scan_line (target, line);
+  sscanf (line, "HEADER SIZE %x", &header_size);
+
+  ALLOCATE (header, char, header_size);
+
+  // read the full header
+  fseeko (target, 0, SEEK_SET);
+  fread (header, 1, header_size, target);
+
+  ptr = header;
+  ptr = strchr (ptr, '\n'); ptr ++; // ROC Version
+  ptr = strchr (ptr, '\n'); ptr ++; // HEADER SIZE
+  
+  sscanf (ptr, "N_FILES %d", &Ninput); ptr = strchr (ptr, '\n'); ptr ++; 
+  sscanf (ptr, "N_BLOCKS %d", &Nblocks); ptr = strchr (ptr, '\n'); ptr ++; 
+
+  if (Nfile >= Ninput) {
+    fprintf (stderr, "file number %d not in ROC\n", Nfile);
+    exit (3);
+  }
+
+  // the input files
+  ALLOCATE (inputName, char *, Ninput);
+  ALLOCATE (sizes, off_t, Ninput);
+  ALLOCATE (bytes_read, off_t, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    ALLOCATE (inputName[i], char, 1024);
+    sscanf (ptr, "%*s : %s", inputName[i]); ptr = strchr (ptr, '\n'); ptr ++; 
+    ptr = strchr (ptr, '\n'); ptr ++; // BASE
+    sscanf (ptr, "%*s : "OFF_T_FMT, &sizes[i]); ptr = strchr (ptr, '\n'); ptr ++; 
+    ptr = strchr (ptr, '\n'); ptr ++; // MD5
+    bytes_read[i] = 0;
+  }
+
+  ALLOCATE (input, FILE *, Ninput);
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    input[i] = fopen(inputName[i], "r");
+    myAssert (input[i], "failed to open file");
+  }
+
+  output = fopen (outputName, "w");
+  myAssert (output, "failed to open output");
+
+  ALLOCATE (inputData, char *, Ninput);
+  ALLOCATE (targetData, char, ROC_BLOCKSIZE);
+  ALLOCATE (outputData, char, ROC_BLOCKSIZE);
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    ALLOCATE (inputData[i], char, ROC_BLOCKSIZE);
+  }
+
+  for (n = 0; n < Nblocks; n++) {
+    for (i = 0; i < Ninput; i++) {
+      if (i == Nfile) continue;
+      Nread = MIN (ROC_BLOCKSIZE, sizes[i] - bytes_read[i]);
+      Nbytes = fread (inputData[i], 1, Nread, input[i]);
+      myAssert (Nbytes == Nread, "failed to read data");
+      if (Nread < ROC_BLOCKSIZE) {
+	// if we have reached the end of the file, fill in the rest with NULLs
+	memset (&inputData[i][Nread], 0, ROC_BLOCKSIZE - Nread);
+      }
+      bytes_read[i] += Nread;
+    }
+    fread (targetData, 1, ROC_BLOCKSIZE, target);
+    
+    for (j = 0; j < ROC_BLOCKSIZE; j++) {
+      value = targetData[j];
+      for (i = 0; i < Ninput; i++) {
+	if (i == Nfile) continue;
+	value = value ^ inputData[i][j];
+      }
+      outputData[j] = value;
+    }
+
+    Nwrite = MIN (ROC_BLOCKSIZE, sizes[Nfile] - bytes_read[Nfile]);
+    if (Nwrite == 0) break;
+    Nbytes = fwrite (outputData, 1, Nwrite, output);
+    myAssert (Nbytes == Nwrite, "failed to write");
+    bytes_read[Nfile] += Nbytes;
+  }
+
+  for (i = 0; i < Ninput; i++) {
+    if (i == Nfile) continue;
+    fclose(input[i]);
+  }
+  fclose (output);
+  fclose (target);
+
+  exit (0);
+}
+
+int roc_insert (int argc, char **argv) {
+
+  exit (0);
+}
+
+int roc_delete (int argc, char **argv) {
+
+  exit (0);
+}
+
+/* roc file description:
+
+   header block + data block
+
+   header min length = ROC_HEADER_SIZE (padded with NULLs)
+
+   ROC Version %d
+   NFILES %d
+   FILE_NNN : full path
+   BASE_NNN : basename
+   SIZE_NNN : file size
+   MD5_NNN  : MD5 checksum of file
+   END
+
+   MAX(NNN) = 32?
+   32*1024
+*/
+
+int usage () {
+  fprintf (stderr, "USAGE: roc [mode]\n");
+  fprintf (stderr, " -create (target) (input) (input) (input) ... [options]\n");
+  fprintf (stderr, " -repair (target) (file #) (output\n");
+  fprintf (stderr, " -insert (target) (input)\n");
+  fprintf (stderr, " -delete (target) (file)\n");
+  exit (2);
+}
+
+int print_block (char *header, int *header_size, int *Noff, char *format,...) {
+
+  char tmp;
+  int Nbyte, Nleft;
+  va_list argp;  
+
+  va_start (argp, format);
+  Nbyte = vsnprintf (&tmp, 0, format, argp);
+  va_end (argp);
+
+  Nleft = *header_size - *Noff;
+
+  if (Nbyte >= Nleft) {
+    *header_size += ROC_HEADER_BLOCK + Nbyte;
+    REALLOCATE (header, char, *header_size);
+  }
+  
+  va_start (argp, format);
+  Nbyte = vsnprintf (&header[*Noff], Nleft, format, argp);
+  va_end (argp);
+
+  if (Nbyte >= Nleft) {
+    return (FALSE);
+  }
+
+  *Noff += Nbyte;
+  return (Nbyte);
+}
+
Index: /branches/czw_branch/20101203/PS-IPP-Config/lib/PS/IPP/Config.pm
===================================================================
--- /branches/czw_branch/20101203/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 30117)
+++ /branches/czw_branch/20101203/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 30118)
@@ -1107,7 +1107,8 @@
     }
 
-    if (file_scheme($output) ne 'neb') {
+    my $scheme = file_scheme($output);
+    if (!$scheme or ($scheme ne 'neb')) {
         # non-nebulous file we're done
-        if ($delete_existing) {
+        if ($delete_existing and $self->file_exists($output)) {
             if (!$self->file_delete($output)) {
                 carp "failed to delete $output";
@@ -1181,5 +1182,6 @@
     my $copies = shift;
 
-    if (file_scheme($file) ne 'neb') {
+    my $scheme = file_scheme($file);
+    if (!$scheme or ($scheme ne 'neb')) {
         carp "cannot replicate non-neulous file: $file";
         return 0;
Index: /branches/czw_branch/20101203/dbconfig/changes.txt
===================================================================
--- /branches/czw_branch/20101203/dbconfig/changes.txt	(revision 30117)
+++ /branches/czw_branch/20101203/dbconfig/changes.txt	(revision 30118)
@@ -1989,4 +1989,8 @@
 UPDATE dbversion set schema_version = '1.1.66',  updated= CURRENT_TIMESTAMP();
 
+-- output format for publishing / unique name for clients
+ALTER TABLE publishClient ADD name VARCHAR(64) UNIQUE; -- (Bill's request)
+ALTER TABLE publishClient ADD output_format SMALLINT NOT NULL default 1;
+
 -- Version 1.1.67
 
Index: /branches/czw_branch/20101203/dbconfig/notes.txt
===================================================================
--- /branches/czw_branch/20101203/dbconfig/notes.txt	(revision 30117)
+++ /branches/czw_branch/20101203/dbconfig/notes.txt	(revision 30118)
@@ -8,4 +8,5 @@
    * build ippbd ('make src' in dbconfig)
    * check in dbconfig, ippdb, and ippTools
+   * update dbversion.schema.version (added by bills)
 
 2007.06.04 : EAM
Index: /branches/czw_branch/20101203/dbconfig/publish.md
===================================================================
--- /branches/czw_branch/20101203/dbconfig/publish.md	(revision 30117)
+++ /branches/czw_branch/20101203/dbconfig/publish.md	(revision 30118)
@@ -9,4 +9,6 @@
     workdir      STR         255
     comment      STR         255
+    name	 STR	     64
+    output_format S16	     0
 END              
                  
Index: /branches/czw_branch/20101203/ippMonitor/raw/czartool_labels.php
===================================================================
--- /branches/czw_branch/20101203/ippMonitor/raw/czartool_labels.php	(revision 30117)
+++ /branches/czw_branch/20101203/ippMonitor/raw/czartool_labels.php	(revision 30118)
@@ -64,5 +64,5 @@
 include 'version.php';
 echo "</p>";
-echo "<p  align=\"center\"> Current status of the IPP as of $lastUpdateTime (faults are shown in parentheses). <br>Documentation can be found <a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/Processing\">here</a> and cluster load monitored <a href=\"http://ganglia.pan-starrs.ifa.hawaii.edu/?r=hour&s=descending&c=IPP%2520Production\">here</a><br>Current nightly science status: $nsStatus<br>Use <a href=\"$link\"> $plotTypeLink</a> plots <br/><a href=\"http://ipp004.ifa.hawaii.edu/clusterMonitor/top.html\">Who uses the cluster?</a></p>";
+echo "<p  align=\"center\"> Current status of the IPP as of $lastUpdateTime (faults are shown in parentheses). <br>Documentation can be found <a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/Processing\">here</a> and cluster load monitored <a href=\"http://ganglia.pan-starrs.ifa.hawaii.edu/?r=hour&s=descending&c=IPP%2520Production\">here</a><br>Current nightly science status: $nsStatus<br>Use <a href=\"$link\"> $plotTypeLink</a> plots <br/><a href=\"http://ipp004.ifa.hawaii.edu/clusterMonitor/top.html\">Who uses the cluster?</a><br><a href=\"http://ipp004.ifa.hawaii.edu/ippMetrics\">IPP Metrics</a><br/><a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/PS1_IPP_CzarLogs\">Czar log pages</a></p>";
 
 
@@ -399,4 +399,7 @@
         ."&plottype=".$plotType;
 
+    $searchState = "new";
+    if ($server == "update") $searchState = "update";
+
     // write rows
     foreach ($labels as &$thisLabel) {
@@ -437,25 +440,25 @@
         write_table_cell($class, '%s', $anyFaults ? $link : "", $str);
 
-        $link = "failedChipProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&chipRun.label=" . $thisLabel . "&chipRun.state=new";
+        $link = "failedChipProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&chipRun.label=" . $thisLabel . "&chipRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "chip", $str, $anyFaults);
         write_table_cell($class, '%s', $anyFaults ? $link : "", $str);
 
-        $link = "failedCamProcessedExp.php?pass=" . $pass . "&proj=" . $proj . "&camRun.label=" . $thisLabel . "&camRun.state=new";
+        $link = "failedCamProcessedExp.php?pass=" . $pass . "&proj=" . $proj . "&camRun.label=" . $thisLabel . "&camRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "cam", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link =  "failedFakeProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&fakeRun.label=" . $thisLabel . "&fakeRun.state=new";
+        $link =  "failedFakeProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&fakeRun.label=" . $thisLabel . "&fakeRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "fake", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link = "failedWarpSkyfiles.php?pass=" . $pass . "&proj=" . $proj . "&warpRun.label=" . $thisLabel . "&warpRun.state=new";
+        $link = "failedWarpSkyfiles.php?pass=" . $pass . "&proj=" . $proj . "&warpRun.label=" . $thisLabel . "&warpRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "warp", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
 
-        $link = "failedStackSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&stackRun.label=" . $thisLabel . "&stackRun.state=new";
+        $link = "failedStackSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&stackRun.label=" . $thisLabel . "&stackRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "stack", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link = "failedDiffSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&diffRun.label=" . $thisLabel . "&diffRun.state=new";
+        $link = "failedDiffSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&diffRun.label=" . $thisLabel . "&diffRun.state=".$searchState;
         getStateAndFaults($db, $thisLabel, $selectedState, "diff", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
@@ -605,5 +608,6 @@
         ."&allservercmd=stop";
 
-    write_table_cell($class, '%s', $link, "Stop all");
+    $link = ""; # TODO removed links temporarily
+        write_table_cell($class, '%s', $link, "Stop all");
     $link = "czartool_labels.php?pass=".$pass
         ."&proj=".$proj
@@ -613,5 +617,6 @@
         ."&allservercmd=run";
 
-    write_table_cell($class, '%s', $link, "Run all");
+    $link = ""; # TODO removed links temporarily
+        write_table_cell($class, '%s', $link, "Run all");
     echo "</tr>\n";
 
@@ -628,5 +633,6 @@
             ."&plottype=".$plotType;
 
-        write_table_cell($class, '%s', $link, $server);
+        $link = ""; # TODO removed links temporarily
+            write_table_cell($class, '%s', $link, $server);
         write_table_cell($class, '%s', "", $alive ? "yes" : "NO");
 
@@ -644,5 +650,6 @@
 
                 $link = $link . "stop";
-                write_table_cell($class, '%s', $link, "stop");
+                $link = ""; # TODO removed links temporarily
+                    write_table_cell($class, '%s', $link, "stop");
                 write_table_cell($class, '%s', "", "");
             }
@@ -651,5 +658,6 @@
                 $link = $link . "run";
                 write_table_cell($class, '%s', "", "");
-                write_table_cell($class, '%s', $link, "run");
+                $link = ""; # TODO removed links temporarily
+                    write_table_cell($class, '%s', $link, "run");
             }
         }
@@ -759,21 +767,21 @@
 ###########################################################################
 function showReplicationsStatus($replHost, $replUser, $replPassword, $replDatabaseName) {
-  #print "<br>$replHost, $replUser, $replPassword, $replDatabaseName<br/>";
-  $dbRepl = DB::connect("mysql://$replUser:$replPassword@$replHost");
-  if (PEAR::isError($dbRepl)) {
-    die("MySQL DB connection error: Check the configuration for $replDatabaseName");
-  }
-  $res = $dbRepl->query('SHOW SLAVE STATUS');
-  while ($res->fetchInto($row)) {
-    # Have a look for Last_Errno in http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html
-    $errorStatusInMySql = $row[18];
-    $replStatus = ($errorStatusInMySql==0?"OK":"<font color=\"red\">PROBLEM</font>");
-    echo "<tr><td>$replDatabaseName</td><td>$replStatus</td></tr>";
-    if ($errorStatusInMySql!=0) {
-      echo "<tr><td colspan=\"2\">Connect to $replDatabaseName replication host, execute 'SHOW SLAVE STATUS', and fix the problem.<br/>";
-      echo "Information <a href=\"http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html\">here</a></td></tr>";
-    }
-  }
-  $dbRepl->disconnect();
+    #print "<br>$replHost, $replUser, $replPassword, $replDatabaseName<br/>";
+    $dbRepl = DB::connect("mysql://$replUser:$replPassword@$replHost");
+    if (PEAR::isError($dbRepl)) {
+        die("MySQL DB connection error: Check the configuration for $replDatabaseName");
+    }
+    $res = $dbRepl->query('SHOW SLAVE STATUS');
+    while ($res->fetchInto($row)) {
+        # Have a look for Last_Errno in http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html
+        $errorStatusInMySql = $row[18];
+        $replStatus = ($errorStatusInMySql==0?"OK":"<font color=\"red\">PROBLEM</font>");
+        echo "<tr><td>$replDatabaseName</td><td>$replStatus</td></tr>";
+        if ($errorStatusInMySql!=0) {
+            echo "<tr><td colspan=\"2\">Connect to $replDatabaseName replication host, execute 'SHOW SLAVE STATUS', and fix the problem.<br/>";
+            echo "Information <a href=\"http://dev.mysql.com/doc/refman/5.0/en/show-slave-status.html\">here</a></td></tr>";
+        }
+    }
+    $dbRepl->disconnect();
 }
 
Index: /branches/czw_branch/20101203/ippMonitor/raw/site.php.in
===================================================================
--- /branches/czw_branch/20101203/ippMonitor/raw/site.php.in	(revision 30117)
+++ /branches/czw_branch/20101203/ippMonitor/raw/site.php.in	(revision 30118)
@@ -27,5 +27,5 @@
 $REPL_DBNAME_GPC1 = "gpc1";
 
-$REPL_HOST_NEBULOUS = "ipp0222.IfA.Hawaii.Edu";
+$REPL_HOST_NEBULOUS = "ippdb02.IfA.Hawaii.Edu";
 $REPL_USER_NEBULOUS = "ippMonitor";
 $REPL_PASSWORD_NEBULOUS = "ippMonitor";
Index: /branches/czw_branch/20101203/ippScripts/scripts/automate_stacks.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/automate_stacks.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/automate_stacks.pl	(revision 30118)
@@ -1355,5 +1355,5 @@
     my ($label,$workdir,$obs_mode,$object,$comment,$tess_id,$dist_group,$data_group,$reduction) = get_tool_parameters($date,$target);
 
-    if ($target eq 'OSS') {
+    if (($target eq 'OSS')||($target eq 'SweetSpot')) {
 	my $db = init_gpc_db();
 
@@ -1372,6 +1372,7 @@
 	    
 	    if (($#{ $warps } + 1) % 2 != 0) {
-		print STDERR "Number of input warps to make OSS diffs is not even! $#{ $warps }\n";
-		last;
+		print STDERR "Number of input warps to make OSS diffs is not even! $this_object $#{ $warps }\n";
+#		last;
+		next;
 	    }
 	    
Index: /branches/czw_branch/20101203/ippScripts/scripts/camera_exp.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/camera_exp.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/camera_exp.pl	(revision 30118)
@@ -378,5 +378,6 @@
         $ipprc->file_exists($file);
 
-    if ($replicate and (file_scheme($file) eq 'neb')) {
+    my $scheme = file_scheme($file);
+    if ($replicate and $scheme and (file_scheme($file) eq 'neb')) {
         $ipprc->replicate_file($file) or &my_die("failed to replicate: $file\n",  $cam_id, $PS_EXIT_SYS_ERROR);
     }
Index: /branches/czw_branch/20101203/ippScripts/scripts/chip_imfile.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/chip_imfile.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/chip_imfile.pl	(revision 30118)
@@ -159,5 +159,4 @@
         if (storage_object_exists($configuration, \$gone)) {
             if ($gone) {
-                rename_gone_file($configuration);
                 $configuration = prepare_output('PPIMAGE.CONFIG', $outroot, $class_id, 1);
                 # if we dump the config we need to insure that the config dump represents
@@ -177,4 +176,7 @@
     $ipprc->delete_destreak_backup_file($outputWeight)
         or &my_die("failed to delete existing destreak backup weight file", $exp_id, $chip_id, $class_id, $PS_EXIT_UNKNOWN_ERROR);
+
+    # don't do binned images when updating unless we are starting from scratch.
+    $do_binned_images = 0 unless $dump_config;
 }
 if ($do_binned_images) {
@@ -491,5 +493,7 @@
         check_output($configuration, 1) if $dump_config;
         check_output($backmdl, 1) if $outputBackmdlExpect;
-        check_output($pattern, 1) if $outputPatternExpect;
+	# allow the pattern file to be missing if run state is update older data doesn't have one
+	# I should parse the config dump file to calculate the 'Expect' variables
+        check_output($pattern, 1, $run_state eq 'update') if $outputPatternExpect;
         if ($do_photom) {
             check_output($outputSources, 1);
@@ -556,5 +560,4 @@
             if ($gone) {
                 carp "WARNING: photometry sources storage object exists but all instances are permanently gone";
-                rename_gone_file($outputSources);
                 $make_sources = 1;
             }
@@ -579,5 +582,4 @@
             if ($gone) {
                 carp "WARNING: PSF storage object exists but all instances are permanently gone";
-                rename_gone_file($outputPsf);
                 $make_psf = 1;
             }
@@ -613,6 +615,9 @@
 sub storage_object_exists
 {
+    return 0 if !$neb;
+
     my $file = shift;
     my $ref_all_gone = shift;
+
 
     my $exists = $neb->storage_object_exists($file);
@@ -678,14 +683,4 @@
     return 1;
 }
-sub rename_gone_file
-{
-    # check whether the only instance of file is on a lost volume
-    # XXX: we don't have a proper interface for this. 
-    # For now try to use Bill's hack: the script 'whichnode'
-
-    my $file = shift;
-    $neb->move($file, "$file.gone") or 
-                    &my_die("failed to rename: $file", $exp_id, $chip_id, $class_id, $PS_EXIT_CONFIG_ERROR);
-}
 
 # Prepare to write to an output file
@@ -711,4 +706,5 @@
     my $file = shift;
     my $replicate = shift;
+    my $allow_missing = shift;
 
     if (!defined $file) {
@@ -716,7 +712,15 @@
     }
 
-    &my_die("Couldn't find expected output file: $file",  $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($file);
-
-    if ($replicate and (file_scheme($file) eq 'neb')) {
+    my $exists = $ipprc->file_exists($file);
+
+    if (!$exists) {
+        if ($allow_missing) {
+            carp("Couldn't find expected output_file: $file but continuing anyways\n");
+            return 1;
+        }
+        &my_die("Couldn't find expected output file: $file",  $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+    }
+
+    if ($replicate and $neb) {
         $ipprc->replicate_file($file) or &my_die("failed to replicate: $file\n",  $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
     }
Index: /branches/czw_branch/20101203/ippScripts/scripts/dist_bundle.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/dist_bundle.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/dist_bundle.pl	(revision 30118)
@@ -62,4 +62,6 @@
 my $streaksrelease   = can_run('streaksrelease') or (warn "Can't find streaksrelease" and $missing_tools = 1);
 my $bgtool   = can_run('bgtool') or (warn "Can't find bgtool" and $missing_tools = 1);
+my $file_cmd   = can_run('file') or (warn "can't find program file" and $missing_tools = 1);
+my $zcat   = can_run('zcat') or (warn "can't find program zcat" and $missing_tools = 1);
 if ($missing_tools) {
     warn("Can't find required tools.");
@@ -526,8 +528,42 @@
                     $PS_EXIT_CONFIG_ERROR) if (!$resolved);
 
+    &my_die("config dump file resolved but not accessible: $config_file_rule", $component,
+                    $PS_EXIT_CONFIG_ERROR) if !$ipprc->file_exists($resolved);
+
+    my $mdc_compressed;
+    {
+        my $command = "$file_cmd $resolved";
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform $command: $error_code", $component, $error_code);
+        }
+        my $output = join "", @$stdout_buf;
+        # XXX: may need to to make this more robust
+        $mdc_compressed = ($output =~ /gzip/);
+    }
+    my $inName;
+    if ($mdc_compressed) {
+        my $tmpfile;
+        ($tmpfile, $inName) = tempfile( "/tmp/bundle.XXXX", UNLINK => !$save_temps );
+        close($tmpfile) or &my_die("failed to close $inName", $component, $PS_EXIT_UNKNOWN_ERROR);
+
+        my $command = "$zcat $resolved > $inName";
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform $command: $error_code", $component, $error_code);
+        }
+
+
+    } else {
+        $inName = $resolved;
+    }
+    my $in = open_with_retries($inName);
+
     # we don't use the mdc parser because the perl parser is way is too slow for complicated config
     # files like this
-    my $in = open_with_retries($resolved);
-
     my $line;
     while ($line = <$in>) {
Index: /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak.pl	(revision 30118)
@@ -309,5 +309,8 @@
         }
 
-        $sources = $ipprc->filename("PSPHOT.OUTPUT",  $path_base, $class_id);
+        # only destreak cmf file if this is a new run
+        if ($run_state eq 'new') {
+            $sources = $ipprc->filename("PSPHOT.OUTPUT",  $path_base, $class_id);
+        }
 
     } elsif ($stage eq "chip_bg") {
Index: /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_defineruns.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_defineruns.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_defineruns.pl	(revision 30118)
@@ -78,5 +78,5 @@
     foreach my $label (@labels) {
         my $command = "$magicdstool -definebyquery -stage $stage -workdir $workdir -label $label";
-        $command .= " -dry_run" if $no_update;
+        $command .= " -pretend" if $no_update;
         $command .= " -limit $stage_limit" if $stage_limit;
         $command .= " -set_label $label";
Index: /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_revert.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_revert.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/magic_destreak_revert.pl	(revision 30118)
@@ -191,5 +191,4 @@
     $image  = $ipprc->filename("PPIMAGE.CHIP", $path_base, $class_id);
     $weight = $ipprc->filename("PPIMAGE.CHIP.VARIANCE", $path_base, $class_id);
-    $sources = $ipprc->filename("PSPHOT.OUTPUT", $path_base, $class_id);
 
     # we use the mask output from the camera stage for input and replace
@@ -204,4 +203,10 @@
     }
 
+    # only revert sources if this is a new run, not one being updated
+    if ($run_state eq 'new') {
+        $sources = $ipprc->filename("PSPHOT.OUTPUT", $path_base, $class_id);
+        $bsources = $ipprc->filename("PSPHOT.OUTPUT", $backup_path_base, $class_id);
+    }
+
     $bimage  = $ipprc->filename("PPIMAGE.CHIP", $backup_path_base, $class_id);
     # This is somewhat kludgey but it works whether the mask is camera mask or chip mask
@@ -209,5 +214,4 @@
     $bch_mask= $ipprc->filename("PPIMAGE.CHIP.MASK", $backup_path_base, $class_id);
     $bweight = $ipprc->filename("PPIMAGE.CHIP.VARIANCE", $backup_path_base, $class_id);
-    $bsources = $ipprc->filename("PSPHOT.OUTPUT", $backup_path_base, $class_id);
 } elsif ($stage eq "camera") {
     $astrom =  $ipprc->filename("PSASTRO.OUTPUT", $path_base);
Index: /branches/czw_branch/20101203/ippScripts/scripts/publish_file.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/publish_file.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/publish_file.pl	(revision 30118)
@@ -44,4 +44,5 @@
 my ( $pub_id, $camera, $stage, $stage_id, $fileset, $format, $product, $workdir );
 my ( $dbname, $verbose, $no_update, $no_op, $save_temps, $redirect );
+my ( $output_format );
 
 GetOptions(
@@ -59,4 +60,5 @@
     'save-temps'        => \$save_temps, # Save temporary files?
     'redirect-output'   => \$redirect,   # Redirect output to log file?
+    'output_format=i'   => \$output_format, # Output format for ppMops
     ) or pod2usage( 2 );
 
@@ -191,4 +193,5 @@
                      warp_id => $comp->{warp1},
                      diff_id => $comp->{diff_id},
+                     output_format => $comp->{output_format},
                      direction => 1,
         };
@@ -323,5 +326,4 @@
 
     my $command = "$ppMops $input $output";
-    $command .= " -version 1"; # XXX : NOTE: for now, MOPS just wants PS1_DV1 (remove this eventually...)
     $command .= " -exp_name " . $data->{exp_name} if defined $data->{exp_name};
     $command .= " -exp_id " . $data->{exp_id} if defined $data->{exp_id};
@@ -335,4 +337,5 @@
     $command .= " -zp_error " . $data->{zp_err} if defined $data->{zp_err};
     $command .= " -astrom_rms " . $data->{astrom} if defined $data->{astrom};
+    $command .= " -version " . $data->{output_format} if defined $data->{output_format};
 
     unless ($no_op) {
Index: /branches/czw_branch/20101203/ippScripts/scripts/receive_file.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/receive_file.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/receive_file.pl	(revision 30118)
@@ -32,4 +32,5 @@
 my $receivetool = can_run('receivetool') or (warn "Can't find receivetool" and $missing_tools = 1);
 my $dsproductls = can_run('dsfilesetls') or (warn "Can't find dsfilesetls" and $missing_tools = 1);
+my $gunzip = can_run('gunzip') or (warn "Can't find gunzip" and $missing_tools = 1);
 if ($missing_tools) {
     warn("Can't find required tools.");
@@ -404,4 +405,24 @@
     my $workdir = shift;
 
+    my $filecmd_output = `file $src`;
+    &my_die("failed to determinte file type of $src", $file_id, $PS_EXIT_UNKNOWN_ERROR) if !$filecmd_output;
+    chomp $filecmd_output;
+
+    my $tmpName;
+    if ($filecmd_output =~ /gzip/) {
+        my $tmpfile;
+        ($tmpfile, $tmpName) = tempfile( "/tmp/receive.XXXX", UNLINK => !$save_temps );
+        close($tmpfile) or &my_die("failed to close $tmpName", $file_id, $PS_EXIT_UNKNOWN_ERROR);
+
+        my $command = "$gunzip -c $src > $tmpName";
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform $command: $error_code", $component, $error_code);
+        }
+        $src = $tmpName;
+    }
+
     open my $IN,  "<$src" or &my_die("failed to open $src for input", $file_id, $PS_EXIT_UNKNOWN_ERROR);
     open my $OUT, ">$dest" or &my_die("failed to open $dest for output", $file_id, $PS_EXIT_UNKNOWN_ERROR);
Index: /branches/czw_branch/20101203/ippScripts/scripts/register_imfile.pl
===================================================================
--- /branches/czw_branch/20101203/ippScripts/scripts/register_imfile.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippScripts/scripts/register_imfile.pl	(revision 30118)
@@ -287,4 +287,15 @@
     if ($burntool_data->{burnable} == 0) {
 	$regtool_update .= " -burntool_state 0 -set_state pending_burntool ";
+	unless ($no_update) {
+	    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		IPC::Cmd::run(command => $regtool_update, verbose => $verbose);
+	    unless ($success) {
+		$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		warn ("Unable to perform regtool -addprocessedimfile: $error_code");
+		exit($error_code);
+	    }
+	} else {
+	    print "skipping command: $command\n";
+	}
     }
     else {
@@ -296,24 +307,15 @@
 	$apply_command .= " --verbose " if $verbose;
 	print "$apply_command\n";
-	my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-	    IPC::Cmd::run(command => $apply_command, verbose => $verbose);
-	unless ($success) {
-	    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-	    warn ("Unable to perform ipp_apply_burntool_single.pl: $error_code");
-	    exit($error_code);
+	unless ($no_update) {
+	    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		IPC::Cmd::run(command => $apply_command, verbose => $verbose);
+	    unless ($success) {
+		$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		warn ("Unable to perform ipp_apply_burntool_single.pl: $error_code");
+		exit($error_code);
+	    }
 	}
     }    
 
-    unless ($no_update) {
-	my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-	    IPC::Cmd::run(command => $regtool_update, verbose => $verbose);
-	unless ($success) {
-	    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-	    warn ("Unable to perform regtool -addprocessedimfile: $error_code");
-	    exit($error_code);
-	}
-    } else {
-	print "skipping command: $command\n";
-    }
 
 }
Index: /branches/czw_branch/20101203/ippTasks/detrend.resid.pro
===================================================================
--- /branches/czw_branch/20101203/ippTasks/detrend.resid.pro	(revision 30117)
+++ /branches/czw_branch/20101203/ippTasks/detrend.resid.pro	(revision 30118)
@@ -136,4 +136,6 @@
 
   task.exec
+    periods -exec $RUNEXEC
+
     book npages detPendingResidImfile -var N
     if ($N == 0) break
@@ -187,4 +189,5 @@
       echo command $run
     end
+    periods -exec 0.05
     command $run
   end
Index: /branches/czw_branch/20101203/ippTasks/publish.pro
===================================================================
--- /branches/czw_branch/20101203/ippTasks/publish.pro	(revision 30117)
+++ /branches/czw_branch/20101203/ippTasks/publish.pro	(revision 30118)
@@ -130,4 +130,5 @@
     book getword publishRun $pageName stage_id -var STAGE_ID
     book getword publishRun $pageName dbname -var DBNAME
+    book getword publishRun $pageName output_format -var OUTPUT_FORMAT
 
     stdout $LOGDIR/publish.run.log
@@ -137,5 +138,5 @@
     strsub $WORKDIR_TEMPLATE @HOST@ $default_host -var WORKDIR
 
-    $run = publish_file.pl --pub_id $PUB_ID --camera $CAMERA --workdir $WORKDIR --product $PRODUCT --stage $STAGE --stage_id $STAGE_ID --redirect-output
+    $run = publish_file.pl --pub_id $PUB_ID --camera $CAMERA --workdir $WORKDIR --product $PRODUCT --stage $STAGE --stage_id $STAGE_ID --output_format $OUTPUT_FORMAT --redirect-output
     add_standard_args run
 
Index: /branches/czw_branch/20101203/ippTasks/register.pro
===================================================================
--- /branches/czw_branch/20101203/ippTasks/register.pro	(revision 30117)
+++ /branches/czw_branch/20101203/ippTasks/register.pro	(revision 30118)
@@ -466,5 +466,5 @@
     $today = `date -u +%Y-%m-%d`
 # debugging purposes
-    $today = "2010-12-06"
+#    $today = "2010-12-06"
     $run = $run -date $today -valid_burntool $valid_burntool_value
     if ($DB:n == 0)
@@ -478,5 +478,5 @@
     end
 
-    echo $run
+#    echo $run
     add_poll_args run
     command $run
Index: /branches/czw_branch/20101203/ippToPsps/docs/loadingSummary.txt
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/docs/loadingSummary.txt	(revision 30118)
+++ /branches/czw_branch/20101203/ippToPsps/docs/loadingSummary.txt	(revision 30118)
@@ -0,0 +1,21 @@
+***********************************************************
+*    Summary of IPP->PSPS loading as of 2010-12-09 12:05:49
+*    DVO Db = 'ThreePi.V1'
+*    Exposures between 105437 and 213141
+*
+* total Exposures                            = 35973
+*   merged into PSPS                         = 32082
+*   un-merged                                = 3890
+*     unprocessed by ippToPsps               = 3351
+*       missing SMF files                    = 518
+*       available SMF files                  = 2833
+*     processed by ippToPsps                 = 539
+*       not on datastore                     = 4
+*       on datastore                         = 535
+*         not loaded to ODM                  = 19
+*         loaded to ODM but rejected         = 516
+*           under -30 dec limit              = 493
+*           remaining ODM failures           = 23
+*
+***********************************************************
+
Index: /branches/czw_branch/20101203/ippToPsps/perl/checkOdmStatus.pl
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/perl/checkOdmStatus.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippToPsps/perl/checkOdmStatus.pl	(revision 30118)
@@ -39,4 +39,7 @@
         );
 
+if (@ARGV) {
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
 if (!defined $product) {
     print "* OPTIONAL: a datastore product name            -p <name>\n";
@@ -159,7 +162,6 @@
         $numBatchesToCheck++;
 
-        # if not merged then update by polling ODM for status
+        # if not merged or failed load, then update by polling ODM for status
         if (!$merged && !$loadFailed) {
-
             if (checkODM($batch->getName(), \$loadedToOdm, \$loadFailed, \$mergeWorthy, \$merged)) {
                 
Index: /branches/czw_branch/20101203/ippToPsps/perl/exposureSummary.pl
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/perl/exposureSummary.pl	(revision 30118)
+++ /branches/czw_branch/20101203/ippToPsps/perl/exposureSummary.pl	(revision 30118)
@@ -0,0 +1,213 @@
+#!/usr/bin/env perl
+
+# script to provide a summary of loading status given an upper and lower exposure ID limit
+
+use warnings;
+use strict;
+
+use LWP::UserAgent;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use File::Temp qw(tempfile);
+use ippToPsps::IppToPspsDb;
+use ippToPsps::Gpc1Db;
+use ippToPsps::DetectionBatch;
+
+my $dvoDb = undef;
+my $beginExp = undef;
+my $endExp = undef;
+my $verbose = undef;
+my $checkNeb = undef;
+my $save_temps = undef;
+
+GetOptions(
+        'startexp|b=s' => \$beginExp,
+        'endexpi|e=s' => \$endExp,
+        'dvodb|d=s' => \$dvoDb,
+        'checkNeb|n' => \$checkNeb,
+        'verbose|v' => \$verbose,
+        'save_temps|s' => \$save_temps
+        );
+
+
+my $quit = 0;
+print "\n*******************************************************************************\n";
+print "* \n";
+if (@ARGV) {
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
+if (!defined $beginExp) {
+    $quit = 1;
+    print "* REQUIRED: a begin exp_id                              -b <name>\n";
+}
+if (!defined $endExp) {
+    $quit = 1;
+    print "* REQUIRED: an end exp_id                               -e <name>\n";
+}
+if (!defined $dvoDb) {
+    $quit = 1;
+    print "* REQUIRED: a dvo Db name                               -d <name>\n";
+}
+if (!defined $checkNeb) {
+    $checkNeb = 0;
+    print "* OPTIONAL: check nebulous for unprocessed exposures    -n      (default = $checkNeb)\n";
+}
+if (!defined $verbose) {
+    $verbose = 0;
+    print "* OPTIONAL: run in verbose mode                         -v      (default = $verbose)\n";
+}
+if (!defined $save_temps) {
+    $save_temps = 0;
+    print "* OPTIONAL: keep temp files                             -t      (default = $save_temps)\n";
+}
+print "*\n*******************************************************************************\n";
+
+if ($quit) { exit; }
+
+my $gpc1Db = new ippToPsps::Gpc1Db("gpc1", "ippdb01", "ippuser", "ippuser", $verbose, $save_temps);
+my $ippToPspsDb = new ippToPsps::IppToPspsDb("ippToPsps", "ippdb01", "ipp", "ipp", $verbose, $save_temps);
+
+my $exposures;
+#if (!$gpc1Db->getExposureListFromDvoDb($dvoDb, \$exposures, 0)) {exit;}
+
+my $totalExposures = $ippToPspsDb->countExposures($beginExp, $endExp, "PSPS_test", "P2", $dvoDb);
+my $totalMerged = $ippToPspsDb->countMergedExposures($beginExp, $endExp, "PSPS_test", "P2", $dvoDb);
+
+if(!$ippToPspsDb->getUnmergedExposures(\$exposures, $beginExp, $endExp, "PSPS_test", "P2", $dvoDb)) {
+
+    print "No unmerged exposures\n";
+    exit;
+}
+
+my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
+my $timeStamp = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
+
+my $exposure;
+my $totalUnmerged = 0;
+my $totalMergeWorthy = 0;
+my $totalProcessed = 0;
+my $totalOnDatastore = 0;
+my $totalLoadedToOdm = 0;
+my $totalLoadFailed = 0;
+my $totalUnderObjIdLimit = 0;
+my $totalUnprocessed = 0;
+my $totalUnprocessedAvailableSmfs = 0;
+my $totalOdmFailures = 0;
+my $totalUnprocessedMissingSmfs = 0;
+
+
+open (UNPRO, ">unprocessedExposures.txt") or print "* Problem opening data file for unprocessed exposures\n";
+open (ODMFAIL, ">odmFailures.txt") or print "* Problem opening data file for ODM failures\n";
+
+if ($checkNeb) {
+
+    open (MISSSMF, ">missingSmfs.txt") or print "* Problem opening data file for missing smfs\n";
+    open (NOTMISSSMF, ">notMissingSmfs.txt") or print "* Problem opening data file for missing smfs\n";
+}
+
+foreach $exposure ( @{$exposures} ) {
+    my ($batchId, $expId) = @{$exposure};
+
+    if ($ippToPspsDb->isExposureMerged($expId)) {next;}
+
+    $totalUnmerged++;
+    if ($verbose) {print "$totalUnmerged | $expId \n"; }
+
+    if ($ippToPspsDb->isExposureProcessed($expId)) {
+
+        $totalProcessed++;
+
+        if ($ippToPspsDb->isExposureAlreadyPublished($expId)) {
+
+            $totalOnDatastore++;
+
+            if ($ippToPspsDb->isExposureLoadedToOdm($expId)) {
+
+                $totalLoadedToOdm++;
+
+                if ($ippToPspsDb->didLoadFail($expId)) {
+
+                    $totalLoadFailed++;
+                }
+                if ($ippToPspsDb->isMinObjIdUnderLimit($expId)) {
+
+                    $totalUnderObjIdLimit++;
+                }
+                else {
+
+                    $totalOdmFailures++;
+                    print ODMFAIL "$expId\n";
+                }
+            }
+        }
+    }
+    else {
+
+
+        $totalUnprocessed++;
+        print UNPRO "$expId\n";
+
+        # if flag is set, then attempt to get smf file from nebulous for this unprocessed exposure
+        if ($checkNeb) {
+
+            my $detectionBatch = ippToPsps::DetectionBatch->existing(
+                    "GPC1",
+                    $gpc1Db,
+                    $batchId,
+                    $ippToPspsDb,
+                    ".",
+                    $verbose,
+                    $save_temps);
+
+
+            my $path = $detectionBatch->getSmfFile();
+            if (!$path) {
+                print "no smf file for $expId\n";
+
+                $totalUnprocessedMissingSmfs++;
+                print MISSSMF "$expId\n";
+            }
+            else {
+
+                $totalUnprocessedAvailableSmfs++;
+                print NOTMISSSMF "$expId\n";
+
+            }
+        }
+
+    }
+}
+
+close(UNPRO);
+close(ODMFAIL);
+if ($checkNeb) {
+
+    close(MISSSMF);
+    close(NOTMISSSMF);
+}
+my $totalProcessedNotOnDatastore = $totalProcessed - $totalOnDatastore;
+my $totalOnDatastoreNotLoaded = $totalOnDatastore - $totalLoadedToOdm;
+print "***********************************************************\n";
+print "*    Summary of IPP->PSPS loading as of $timeStamp\n"; 
+print "*    DVO Db = '$dvoDb'\n";
+print "*    Exposures between $beginExp and $endExp\n";
+print "*\n";
+print "* total Exposures                            = $totalExposures\n";
+print "*   merged into PSPS                         = $totalMerged\n";
+print "*   un-merged                                = $totalUnmerged\n";
+print "*     unprocessed by ippToPsps               = $totalUnprocessed\n";
+if ($checkNeb) {
+    print "*       missing SMF files                    = $totalUnprocessedMissingSmfs\n";
+    print "*       available SMF files                  = $totalUnprocessedAvailableSmfs\n";
+}
+print "*     processed by ippToPsps                 = $totalProcessed\n";
+print "*       not on datastore                     = $totalProcessedNotOnDatastore\n";
+print "*       on datastore                         = $totalOnDatastore\n";
+print "*         not loaded to ODM                  = $totalOnDatastoreNotLoaded\n";
+print "*         loaded to ODM but rejected         = $totalLoadedToOdm\n";
+print "*           under -30 dec limit              = $totalUnderObjIdLimit\n";
+print "*           remaining ODM failures           = $totalOdmFailures\n";
+print "*\n";
+print "***********************************************************\n";
+
+
Index: /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/DetectionBatch.pm
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 30117)
+++ /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/DetectionBatch.pm	(revision 30118)
@@ -78,5 +78,5 @@
     # get neb path of smf file
     my $nebPath = $self->{_gpc1Db}->getCameraStageSmfForThisDvoDb($self->{_dvoDb}, $self->{_expId});
-    if (!$nebPath) { return 0; }
+    if (!$nebPath) { return undef; }
 
     # get real filename from neb 'key'
Index: /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/IppToPspsDb.pm
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/IppToPspsDb.pm	(revision 30117)
+++ /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps/IppToPspsDb.pm	(revision 30118)
@@ -11,5 +11,5 @@
 ###########################################################################
 #
-# Returns a list of batches that have been processed and loaded to datastore
+# Returns a list of batches created within the provided dates
 #
 ###########################################################################
@@ -39,7 +39,5 @@
     $query->execute;
     ${$batches} = $query->fetchall_arrayref();
-    my $count = scalar @{${$batches}};
-
-   return $count;
+    return scalar @{${$batches}};
 }
 
@@ -72,7 +70,75 @@
     $query->execute;
     ${$batches} = $query->fetchall_arrayref();
-    my $count = scalar @{${$batches}};
-
-   return $count;
+    return scalar @{${$batches}};
+}
+
+###########################################################################
+#
+# Returns a count of all distinct exposures between provided limits
+#
+###########################################################################
+sub countExposures {
+    my ($self, $fromExp, $toExp, $datastoreProduct, $batchType, $dvoDb) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(distinct exp_id) 
+        FROM batches 
+        WHERE exp_id >= $fromExp
+        AND exp_id <= $toExp 
+        AND dvo_db = '$dvoDb' 
+        AND batch_type = '$batchType' 
+        AND datastore_product = '$datastoreProduct' 
+SQL
+
+    $query->execute;
+    return scalar $query->fetchrow_array();
+}
+
+###########################################################################
+#
+# Returns a count of exposures (between provided limits) that have been merged
+#
+###########################################################################
+sub countMergedExposures {
+    my ($self, $fromExp, $toExp, $datastoreProduct, $batchType, $dvoDb) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(distinct exp_id) 
+        FROM batches 
+        WHERE exp_id >= $fromExp
+        AND exp_id <= $toExp 
+        AND dvo_db = '$dvoDb' 
+        AND batch_type = '$batchType' 
+        AND datastore_product = '$datastoreProduct' 
+        AND merged
+SQL
+
+    $query->execute;
+    return scalar $query->fetchrow_array();
+}
+
+###########################################################################
+#
+# Returns a list of exposures (between provided limits) that have not been merged
+#
+###########################################################################
+sub getUnmergedExposures {
+    my ($self, $exposures, $fromExp, $toExp, $datastoreProduct, $batchType, $dvoDb) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT batch_id, exp_id 
+        FROM batches 
+        WHERE exp_id >= $fromExp
+        AND exp_id <= $toExp 
+        AND dvo_db = '$dvoDb' 
+        AND batch_type = '$batchType' 
+        AND datastore_product = '$datastoreProduct' 
+        AND !merged
+        GROUP BY exp_id
+SQL
+
+    $query->execute;
+    ${$exposures} = $query->fetchall_arrayref();
+    return scalar @{${$exposures}};
 }
 
@@ -166,4 +232,103 @@
 #######################################################################################
 #
+# Checks whether this exposure failed to load to the ODM
+#
+########################################################################################
+sub didLoadFail {
+    my ($self, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(*) 
+        FROM batches 
+        WHERE exp_id = $expId
+        AND load_failed
+SQL
+
+    $query->execute;
+
+    return scalar $query->fetchrow_array();
+}
+
+#######################################################################################
+#
+# Checks whether this exposure has a min object ID under old PSPS hard limit of 72010000000000001
+#
+########################################################################################
+sub isMinObjIdUnderLimit {
+    my ($self, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(*) 
+        FROM batches 
+        WHERE exp_id = $expId
+        AND min_obj_id < 72010000000000001
+SQL
+
+    $query->execute;
+
+    return scalar $query->fetchrow_array();
+}
+#######################################################################################
+#
+# Checks whether this exposure has been processed
+#
+########################################################################################
+sub isExposureProcessed {
+    my ($self, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(*) 
+        FROM batches 
+        WHERE exp_id = $expId
+        AND processed
+SQL
+
+    $query->execute;
+
+    return scalar $query->fetchrow_array();
+}
+
+#######################################################################################
+#
+# Checks whether this exposure has been merged 
+#
+########################################################################################
+sub isExposureMerged {
+    my ($self, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(*) 
+        FROM batches 
+        WHERE exp_id = $expId
+        AND merged
+SQL
+
+    $query->execute;
+
+    return scalar $query->fetchrow_array();
+}
+
+#######################################################################################
+#
+# Checks whether this exposure has been loaded to ODM 
+#
+########################################################################################
+sub isExposureLoadedToOdm {
+    my ($self, $expId) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT COUNT(*) 
+        FROM batches 
+        WHERE exp_id = $expId
+        AND loaded_to_ODM
+SQL
+
+    $query->execute;
+
+    return scalar $query->fetchrow_array();
+}
+
+#######################################################################################
+#
 # Checks whether we have successfully processed this exposure and loaded it to the datastore 
 #
@@ -184,4 +349,5 @@
     my $processed = $query->fetchrow_array();
 
+    # TODO can use return scalar $query->fetchrow_array();
     return $processed;
 }
Index: /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps_run.pl
===================================================================
--- /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps_run.pl	(revision 30117)
+++ /branches/czw_branch/20101203/ippToPsps/perl/ippToPsps_run.pl	(revision 30118)
@@ -15,4 +15,5 @@
 use ippToPsps::IppToPspsDb;
 use ippToPsps::Datastore;
+#use ippToPsps::BatchManager;
 
 # globals
@@ -112,4 +113,5 @@
 my $datastore = undef;
 if ($datastoreProduct) {$datastore = new ippToPsps::Datastore($datastoreProduct, $verbose, $save_temps);}
+#my $batchManager = new ippToPsps::BatchManager($ippToPspsDb, $output, $verbose, $save_temps);
 
 # check we can run programs and get camera config
Index: /branches/czw_branch/20101203/ippTools/configure.ac
===================================================================
--- /branches/czw_branch/20101203/ippTools/configure.ac	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/configure.ac	(revision 30118)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.61)
 
-AC_INIT([ipptools], [1.1.65], [ipp-support@ifa.hawaii.edu])
+AC_INIT([ipptools], [1.1.66], [ipp-support@ifa.hawaii.edu])
 AC_CONFIG_SRCDIR([autogen.sh])
 
@@ -18,5 +18,5 @@
 PKG_CHECK_MODULES([PSLIB], [pslib >= 1.1.0])
 PKG_CHECK_MODULES([PSMODULES], [psmodules >= 1.1.0])
-PKG_CHECK_MODULES([IPPDB], [ippdb >= 1.1.65]) 
+PKG_CHECK_MODULES([IPPDB], [ippdb >= 1.1.66]) 
 PKG_CHECK_MODULES([PPSTAMP], [ppstamp >= 0.1.1]) 
 
Index: /branches/czw_branch/20101203/ippTools/share/pubtool_definerun.sql
===================================================================
--- /branches/czw_branch/20101203/ippTools/share/pubtool_definerun.sql	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/share/pubtool_definerun.sql	(revision 30118)
@@ -3,5 +3,6 @@
     client_id,
     stage_id,
-    src_label
+    src_label,
+    output_format
 FROM (
     -- Get diffs to publish
@@ -9,5 +10,6 @@
         client_id,
         diff_id AS stage_id,
-        diffRun.label AS src_label
+        diffRun.label AS src_label,
+	output_format
     FROM publishClient
     JOIN diffRun
@@ -28,5 +30,6 @@
         client_id,
         cam_id AS stage_id,
-        camRun.label AS src_label
+        camRun.label AS src_label,
+	output_format
     FROM publishClient
     JOIN camRun
@@ -43,5 +46,6 @@
         client_id,
         diff_phot_id AS stage_id,
-        diffPhotRun.label AS src_label
+        diffPhotRun.label AS src_label,
+	output_format
     FROM publishClient
     JOIN diffPhotRun
Index: /branches/czw_branch/20101203/ippTools/share/pubtool_pending.sql
===================================================================
--- /branches/czw_branch/20101203/ippTools/share/pubtool_pending.sql	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/share/pubtool_pending.sql	(revision 30118)
@@ -9,4 +9,5 @@
         publishClient.stage,
         publishClient.workdir,
+	publishClient.output_format,
         diffRun.diff_id AS stage_id,
         rawExp.camera,
@@ -35,4 +36,5 @@
         publishClient.stage,
         publishClient.workdir,
+	publishClient.output_format,
         camRun.cam_id AS stage_id,
         rawExp.camera,
@@ -56,4 +58,5 @@
         publishClient.stage,
         publishClient.workdir,
+	publishClient.output_format,
         diffPhotRun.diff_phot_id AS stage_id,
         rawExp.camera,
Index: /branches/czw_branch/20101203/ippTools/share/pxadmin_create_tables.sql
===================================================================
--- /branches/czw_branch/20101203/ippTools/share/pxadmin_create_tables.sql	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/share/pxadmin_create_tables.sql	(revision 30118)
@@ -1645,5 +1645,8 @@
     workdir VARCHAR(255) NOT NULL, -- working directory
     comment VARCHAR(255),            -- for human memory
-    PRIMARY KEY(client_id)
+    name varchar(64) default NULL, -- unique client_id verbose identifier
+    output_format SMALLINT NOT NULL default 1, -- format output versioning
+    PRIMARY KEY(client_id),
+    UNIQUE KEY name (name)
 ) ENGINE=innodb DEFAULT CHARSET=latin1;
 
Index: /branches/czw_branch/20101203/ippTools/share/regtool_pendingexp.sql
===================================================================
--- /branches/czw_branch/20101203/ippTools/share/regtool_pendingexp.sql	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/share/regtool_pendingexp.sql	(revision 30118)
@@ -1,49 +1,54 @@
 SELECT DISTINCT
-    exp_id,
-    tmp_exp_name,
-    tmp_camera,
-    tmp_telescope,
-    state,
-    workdir,
-    workdir_state,
-    reduction,
-    dvodb,
-    tess_id,
-    end_stage,
-    label,
-    camera,
-    filter,
-    obs_mode,
-    obs_group,
-    epoch,
-    dateobs
-FROM
-    (SELECT
-       newExp.*,
-       newImfile.tmp_class_id,
-       rawImfile.tmp_class_id as raw_tmp_class_id,
-       rawImfile.camera,
-       rawImfile.filter,
-       rawImfile.dateobs,
-       rawImfile.obs_mode,
-       rawImfile.obs_group
-    FROM newExp
-    JOIN newImfile
-       USING(exp_id)
-    LEFT JOIN rawExp
-       USING(exp_id)
-    LEFT JOIN rawImfile
-        ON newImfile.exp_id = rawImfile.exp_id
-        AND newImfile.tmp_class_id = rawImfile.tmp_class_id
-    WHERE
-        newExp.state = 'run'
-        AND rawExp.exp_id IS NULL
-	AND rawImfile.data_state = 'full'
--- where hook %s
-    GROUP BY
-        newExp.exp_id
-    HAVING
-        COUNT(newImfile.tmp_class_id) = COUNT(rawImfile.tmp_class_id)
-        AND SUM(rawImfile.fault) = 0
+     exp_id,
+     tmp_exp_name,
+     tmp_camera,
+     tmp_telescope,
+     state,
+     workdir,
+     workdir_state,
+     reduction,
+     dvodb,
+     tess_id,
+     end_stage,
+     label,
+     camera,
+     filter,
+     obs_mode,
+     obs_group,
+     epoch,
+     dateobs
+FROM 
+        (
+        select DISTINCT * from 
+         (
+          select newExp.*,count(newImfile.tmp_class_id) AS new_count
+          from newExp
+          LEFT JOIN newImfile USING (exp_id)
+          LEFT JOIN rawExp USING (exp_id) 
+          where 
+           newExp.state = 'run' AND rawExp.exp_id IS NULL
+          GROUP BY newExp.exp_id
+         ) AS NEWEXPOSURES
+         JOIN 
+         (
+          select DISTINCT newExp.exp_id,
+	  rawImfile.camera,
+	  rawImfile.filter,
+	  rawImfile.dateobs,
+	  rawImfile.obs_mode,
+	  rawImfile.obs_group,
+	  count(rawImfile.tmp_class_id) AS raw_count
+          from newExp
+          LEFT JOIN rawExp USING (exp_id) 
+          LEFT JOIN rawImfile USING (exp_id)
+          where 
+           newExp.state = 'run' AND rawExp.exp_id IS NULL
+           AND rawImfile.data_state = 'full'
+	   -- where hook %s
+          GROUP BY newExp.exp_id
+          HAVING SUM(rawImfile.fault) = 0
+         ) AS RAWEXPOSURES
+	 USING (exp_id)
+        WHERE raw_count = new_count 
+    ) AS Foo
 -- limit hook %s
-    ) as Foo
Index: /branches/czw_branch/20101203/ippTools/src/dettool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/dettool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/dettool.c	(revision 30118)
@@ -572,4 +572,6 @@
     PXOPT_COPY_F64(config->args, where, "-select_moon_phase_min", "moon_phase", ">=");
     PXOPT_COPY_F64(config->args, where, "-select_moon_phase_max", "moon_phase", "<=");
+
+    PXOPT_COPY_STR(config->args, where, "-select_state", "state", "=");
     PXOPT_COPY_STR(config->args, where, "-comment", "comment", "LIKE");
 
Index: /branches/czw_branch/20101203/ippTools/src/dettoolConfig.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/dettoolConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/dettoolConfig.c	(revision 30118)
@@ -138,4 +138,5 @@
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_moon_phase_min",  0,          "define min moon phase", NAN);
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_moon_phase_max",  0,          "define max moon phase", NAN);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_state",           0,          "select by state (default is 'full')", "full");
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-comment",                0,          "search by comment field (LIKE comparison)", NULL);
 
Index: /branches/czw_branch/20101203/ippTools/src/difftool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/difftool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/difftool.c	(revision 30118)
@@ -483,5 +483,5 @@
     psFree(where);
 
-     psStringAppend(&query, "\nORDER by priority DESC, diff_id");
+     psStringAppend(&query, "\nORDER by priority DESC, diff_id, skycell_id");
 
     // treat limit == 0 as "no limit"
@@ -1978,4 +1978,5 @@
     PXOPT_COPY_STR(config->args, stack2Where, "-skycell_id", "stackRun.skycell_id", "==");
     PXOPT_COPY_STR(config->args, stack1Where, "-input_label", "stackRun.label","==");
+    PXOPT_COPY_STR(config->args, stack1Where, "-input_data_group", "stackRun.data_group","==");
     PXOPT_COPY_STR(config->args, stack2Where, "-template_label", "stackRun.label","==");
     PXOPT_COPY_F32(config->args, stack1Where, "-good_frac", "stackSumSkyfile.good_frac", ">=");
@@ -2042,8 +2043,4 @@
     }
 
-    psString queryCopy = psStringCopy(query);
-    psFree(query);
-    query = queryCopy;
-    
     psStringSubstitute(&query, stack1Query, "@STACK1_QUERY@");
     psStringSubstitute(&query, stack2Query, "@STACK2_QUERY@");
@@ -2120,9 +2117,4 @@
 	psStringAppend(&this_stack1Query,"AND %s", thisWhere);
 	psFree(thisWhere);
-
-	psString queryCopy = psStringCopy(query);
-	psFree(query);
-	query = queryCopy;
-    
 
 	psStringSubstitute(&query, this_stack1Query, "@STACK1_QUERY@");
Index: /branches/czw_branch/20101203/ippTools/src/difftoolConfig.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/difftoolConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/difftoolConfig.c	(revision 30118)
@@ -336,4 +336,5 @@
     psMetadataAddStr(definestackstackArgs, PS_LIST_TAIL, "-input_label", 0, "search by stack label for input", NULL);
     psMetadataAddStr(definestackstackArgs, PS_LIST_TAIL, "-template_label", 0, "search by stack label for template", NULL);
+    psMetadataAddStr(definestackstackArgs, PS_LIST_TAIL, "-input_data_group", 0, "search by stack data_group for input", NULL);
     psMetadataAddF32(definestackstackArgs, PS_LIST_TAIL, "-good_frac", 0, "minimum good fraction of skycell", NAN);
     psMetadataAddStr(definestackstackArgs, PS_LIST_TAIL, "-set_workdir", 0, "define workdir (required)", NULL);
Index: /branches/czw_branch/20101203/ippTools/src/magicdstool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/magicdstool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/magicdstool.c	(revision 30118)
@@ -1155,6 +1155,6 @@
 
     psMetadata *where = psMetadataAlloc();
-    // new state
-    PXOPT_LOOKUP_STR(new_state, config->args, "-set_state", false, false);
+    // new state (required
+    PXOPT_LOOKUP_STR(new_state, config->args, "-set_state", true, false);
     // old state (required)
     PXOPT_LOOKUP_STR(state, config->args, "-state", true, false);
Index: /branches/czw_branch/20101203/ippTools/src/magicdstoolConfig.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/magicdstoolConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/magicdstoolConfig.c	(revision 30118)
@@ -163,5 +163,5 @@
     // -clearstatefaults
     psMetadata *clearstatefaultsArgs = psMetadataAlloc();
-    psMetadataAddStr(clearstatefaultsArgs, PS_LIST_TAIL, "-set_state", 0, "new value for state", NULL);
+    psMetadataAddStr(clearstatefaultsArgs, PS_LIST_TAIL, "-set_state", 0, "new value for state (required)", NULL);
     psMetadataAddStr(clearstatefaultsArgs, PS_LIST_TAIL, "-state", 0, "search by state (required)", NULL);
     psMetadataAddS64(clearstatefaultsArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "search by magictool de-streak ID", 0);
Index: /branches/czw_branch/20101203/ippTools/src/pstamptool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/pstamptool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/pstamptool.c	(revision 30118)
@@ -950,9 +950,12 @@
     PXOPT_COPY_S64(config->args, where, "-job_id", "job_id", "==");
     PXOPT_COPY_S64(config->args, where, "-dep_id", "dep_id", "==");
+
+    PXOPT_COPY_S64(config->args, where, "-stage_id", "stage_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-component", "component", "==");
+
     PXOPT_COPY_S32(config->args, where, "-fault",  "pstampDependent.fault", "==");
+
     pxAddLabelSearchArgs(config, where, "-label", "pstampRequest.label", "LIKE");
-    // if (fault_count) {
-        PXOPT_COPY_S32(config->args, where, "-fault_count", "pstampDependent.fault_count", ">=");
-    // }
+    PXOPT_COPY_S32(config->args, where, "-fault_count", "pstampDependent.fault_count", ">=");
 
     // XXX: How about selecting by pstampRequest.label? No. That is too dangerous by itself.
Index: /branches/czw_branch/20101203/ippTools/src/pstamptoolConfig.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/pstamptoolConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/pstamptoolConfig.c	(revision 30118)
@@ -178,4 +178,6 @@
     psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-job_id", 0,       "job_id of jobs to update", 0);
     psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-dep_id", 0,       "dep_id of jobs to update", 0);
+    psMetadataAddS64(stopdependentjobArgs, PS_LIST_TAIL,  "-stage_id", 0,     "stage_id of jobs to update", 0);
+    psMetadataAddStr(stopdependentjobArgs, PS_LIST_TAIL,  "-component", 0,    "component of jobs to update", NULL);
     psMetadataAddS16(stopdependentjobArgs, PS_LIST_TAIL,  "-fault", 0,        "current value for dependent fault", 0);
     psMetadataAddS32(stopdependentjobArgs, PS_LIST_TAIL,  "-fault_count", 0,   "select by fault_count (>=)", 0);
Index: /branches/czw_branch/20101203/ippTools/src/pubtool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/pubtool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/pubtool.c	(revision 30118)
@@ -96,6 +96,8 @@
     PXOPT_LOOKUP_STR(comment, config->args, "-comment",  false, false);
     PXOPT_LOOKUP_BOOL(unmagicked, config->args, "-unmagicked",  false);
-
-    if (!publishClientInsert(config->dbh, 0, 0, product, stage, !unmagicked, workdir, comment)) {
+    PXOPT_LOOKUP_STR(name, config->args, "-name",  false, false);
+    PXOPT_LOOKUP_S16(output_format, config->args, "-output_format",  false, false);
+
+    if (!publishClientInsert(config->dbh, 0, 0, product, stage, !unmagicked, workdir, comment, name, output_format)) {
         psError(PS_ERR_UNKNOWN, false, "Database error");
         return false;
@@ -313,4 +315,5 @@
     PXOPT_COPY_STR(config->args, where, "-stage", "publishClient.stage", "==");
     PXOPT_COPY_STR(config->args, where, "-comment", "publishClient.comment", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-name", "publishClient.name", "LIKE");
     pxAddLabelSearchArgs(config, where, "-label", "publishRun.label", "==");
 
Index: /branches/czw_branch/20101203/ippTools/src/pubtoolConfig.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/pubtoolConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/pubtoolConfig.c	(revision 30118)
@@ -83,4 +83,5 @@
     psMetadataAddBool(pendingArgs, PS_LIST_TAIL, "-simple",  0, "use simple output format?", false);
     psMetadataAddU64(pendingArgs, PS_LIST_TAIL, "-limit",  0, "limit result set", 0);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-name", 0, "search on client name", NULL);
 
     // -add
Index: /branches/czw_branch/20101203/ippTools/src/regtool.c
===================================================================
--- /branches/czw_branch/20101203/ippTools/src/regtool.c	(revision 30117)
+++ /branches/czw_branch/20101203/ippTools/src/regtool.c	(revision 30118)
@@ -300,5 +300,5 @@
   psStringSubstitute(&query,date,"@DATE@");
 
-  fprintf(stderr,"%s",query);
+  //  fprintf(stderr,"%s",query);
 
   if (!p_psDBRunQuery(config->dbh, query)) {
@@ -349,5 +349,8 @@
       psMetadataAddStr(row,PS_LIST_TAIL,"previous_class_id",PS_META_REPLACE,"",previous_class_id);
     }
-    
+    // class_id = NULL sorts to the top of the list, so skip those (incomplete downloads)
+    if (!this_class_id) {
+      continue;
+    }
     // Determine if we've crossed a class_id boundary, as this resets the bits.
     if (previous_class_id) {
@@ -370,7 +373,9 @@
     if ((psMetadataLookupS32(NULL,row,"is_downloaded") != 1)||
 	(psMetadataLookupS32(NULL,row,"is_registered") != 1)) {
+      //      printf("I claim this isn't downloaded or registered? %s %s\n",this_uri,this_class_id);
       ok_to_burn = false;
     }
     if (already_burned == false) {
+      //      printf("already_burned looks false %s %s\n",this_uri,this_class_id);
       ok_to_burn = false;
     }
@@ -398,5 +403,5 @@
     }      
 
-    //    printf("STATUS: %s %s %s %s (%d %d)\n",this_uri,previous_uri,this_class_id,previous_class_id,ok_to_burn,already_burned);
+    //    printf("STATUS: %s %s %s %s (%d %d) %d %d %d\n",this_uri,previous_uri,this_class_id,previous_class_id,ok_to_burn,already_burned,psMetadataLookupS32(NULL,row,"burntool_state"),psMetadataLookupS32(NULL,row,"is_registered"),psMetadataLookupS32(NULL,row,"is_downloaded"));
 
     // If the state of this imfile is not "pending_burntool" then we can't burn it. 
Index: /branches/czw_branch/20101203/ippconfig/gpc1/camera.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/gpc1/camera.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/gpc1/camera.config	(revision 30118)
@@ -164,3 +164,5 @@
 # This value is equal to CONV.POOR | STARCORE | SPIKE | SUSPECT  = 0x5280
 # unfortunately the perl parser won't accept a hex value
-MASK.NO.CENSOR      U32      21120
+MASK.NO.CENSOR               U32      21120
+
+METADATA.COMPRESSION         STR      7f # compression mode (nM): n = 1-9, M = f (filtered), h (Huffman), R (run-length)
Index: /branches/czw_branch/20101203/ippconfig/gpc1/ppImage.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/gpc1/ppImage.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/gpc1/ppImage.config	(revision 30118)
@@ -13,4 +13,5 @@
 NORM.CLASS              STR     CHIP             # How to find the per-class normalizations
 
+NONLIN                  BOOL    FALSE            # apply non-linearity correction 
 OLDDARK                 BOOL    FALSE
 
@@ -279,4 +280,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -308,4 +310,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -337,4 +340,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -367,4 +371,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -392,4 +397,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    FALSE           # Dark subtraction
@@ -415,4 +421,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -438,4 +445,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE
   DARK             BOOL    TRUE            # Dark subtraction
@@ -468,4 +476,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -521,4 +530,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -544,4 +554,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -574,4 +585,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -597,4 +609,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -631,4 +644,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -656,4 +670,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -680,4 +695,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -704,4 +720,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -728,4 +745,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -776,4 +794,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -820,4 +839,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -840,4 +860,5 @@
 PPIMAGE_J1_RESID_B      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -877,4 +898,5 @@
 PPIMAGE_J2_RESID_B        METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -914,4 +936,5 @@
 PPIMAGE_J1_RESID_F      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -950,4 +973,5 @@
 PPIMAGE_J2_RESID_F        METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -991,6 +1015,6 @@
   CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
-  OVERSCAN         BOOL    FALSE           # Overscan subtraction
-  OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1028,4 +1052,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1080,4 +1105,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1109,4 +1135,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -1138,4 +1165,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    TRUE            # apply non-linearity correction 
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1167,4 +1195,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    TRUE            # apply non-linearity correction 
   BIAS               BOOL    FALSE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
Index: /branches/czw_branch/20101203/ippconfig/gpc1/psastro.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/gpc1/psastro.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/gpc1/psastro.config	(revision 30118)
@@ -291,2 +291,6 @@
 	REFSTAR_MASK	BOOL	FALSE
 END
+
+SAS_REFERENCE METADATA
+    PSASTRO.CATDIR              STR      SAS.REF.V1
+END
Index: /branches/czw_branch/20101203/ippconfig/recipes/filerules-mef.mdc
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/filerules-mef.mdc	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/filerules-mef.mdc	(revision 30118)
@@ -276,4 +276,8 @@
 PPSUB.REF.CONV.VARIANCE	OUTPUT {OUTPUT}.refConv.wt.fits          VARIANCE  COMP_WT    FPA        TRUE      NONE
 		      						       		     
+PPSUB.FORCED1.SOURCES   OUTPUT {OUTPUT}.frc1.cmf             	 CMF       NONE       FPA        TRUE      NONE
+PPSUB.FORCED2.SOURCES   OUTPUT {OUTPUT}.frc2.cmf             	 CMF       NONE       FPA        TRUE      NONE
+PPSUB.POS1.SOURCES      OUTPUT {OUTPUT}.pos1.cmf             	 CMF       NONE       FPA        TRUE      NONE
+PPSUB.POS2.SOURCES      OUTPUT {OUTPUT}.pos2.cmf             	 CMF       NONE       FPA        TRUE      NONE
                                                                                      
 PPSTACK.OUTPUT          OUTPUT {OUTPUT}.fits                     IMAGE     COMP_IMG   FPA        TRUE      NONE
Index: /branches/czw_branch/20101203/ippconfig/recipes/filerules-simple.mdc
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/filerules-simple.mdc	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/filerules-simple.mdc	(revision 30118)
@@ -246,4 +246,9 @@
 PPSUB.REF.CONV.VARIANCE      OUTPUT {OUTPUT}.refConv.wt.fits      VARIANCE        NONE       FPA        TRUE      NONE
                                              
+PPSUB.FORCED1.SOURCES        OUTPUT {OUTPUT}.frc1.cmf             CMF             NONE       FPA        TRUE      NONE
+PPSUB.FORCED2.SOURCES        OUTPUT {OUTPUT}.frc2.cmf             CMF             NONE       FPA        TRUE      NONE
+PPSUB.POS1.SOURCES           OUTPUT {OUTPUT}.pos1.cmf             CMF             NONE       FPA        TRUE      NONE
+PPSUB.POS2.SOURCES           OUTPUT {OUTPUT}.pos2.cmf             CMF             NONE       FPA        TRUE      NONE
+
 PPSTACK.OUTPUT.COMP          OUTPUT {OUTPUT}.fits                 IMAGE           COMP_IMG   FPA        TRUE      NONE
 PPSTACK.OUTPUT.RAW           OUTPUT {OUTPUT}.fits                 IMAGE           NONE       FPA        TRUE      NONE
Index: /branches/czw_branch/20101203/ippconfig/recipes/filerules-split.mdc
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/filerules-split.mdc	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/filerules-split.mdc	(revision 30118)
@@ -272,4 +272,9 @@
 PPSUB.REF.CONV.VARIANCE      OUTPUT {OUTPUT}.refConv.wt.fits          VARIANCE        COMP_WT    FPA        TRUE      NONE
                                                                                                       
+PPSUB.FORCED1.SOURCES        OUTPUT {OUTPUT}.frc1.cmf                 CMF             NONE       FPA        TRUE      NONE
+PPSUB.FORCED2.SOURCES        OUTPUT {OUTPUT}.frc2.cmf                 CMF             NONE       FPA        TRUE      NONE
+PPSUB.POS1.SOURCES           OUTPUT {OUTPUT}.pos1.cmf                 CMF             NONE       FPA        TRUE      NONE
+PPSUB.POS2.SOURCES           OUTPUT {OUTPUT}.pos2.cmf                 CMF             NONE       FPA        TRUE      NONE
+
 PPSTACK.OUTPUT.COMP          OUTPUT {OUTPUT}.fits                     IMAGE           COMP_IMG   FPA        TRUE      NONE
 PPSTACK.OUTPUT.NOCOMP        OUTPUT {OUTPUT}.fits                     IMAGE           NONE       FPA        TRUE      NONE
@@ -278,4 +283,5 @@
 PPSTACK.OUTPUT.VARIANCE.COMP OUTPUT {OUTPUT}.wt.fits                  VARIANCE        COMP_WT    FPA        TRUE      NONE
 PPSTACK.OUTPUT.VARIANCE.NOCOMP OUTPUT {OUTPUT}.wt.fits                VARIANCE        NONE       FPA        TRUE      NONE
+
 PPSTACK.OUTPUT.EXP           OUTPUT {OUTPUT}.exp.fits                 IMAGE           EXP        FPA        TRUE      NONE
 PPSTACK.OUTPUT.EXPNUM        OUTPUT {OUTPUT}.num.fits                 MASK            EXPNUM     FPA        TRUE      NONE
Index: /branches/czw_branch/20101203/ippconfig/recipes/nightly_science.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/nightly_science.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/nightly_science.config	(revision 30118)
@@ -82,5 +82,5 @@
   NAME      STR  MD02
   DISTRIBUTION STR MD02
-  TESS      STR MD02
+  TESS      STR MD02.V2
   OBSMODE   STR MD
   OBJECT    STR MD02%
@@ -104,5 +104,5 @@
   NAME      STR MD04
   DISTRIBUTION STR MD04
-  TESS      STR MD04
+  TESS      STR MD04.V2
   OBSMODE   STR MD
   OBJECT    STR MD04%
Index: /branches/czw_branch/20101203/ippconfig/recipes/ppImage.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/ppImage.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/ppImage.config	(revision 30118)
@@ -4,6 +4,6 @@
 
 # List of tasks to perform
+OVERSCAN           BOOL    TRUE            # Overscan subtraction
 NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
-OVERSCAN           BOOL    TRUE            # Overscan subtraction
 NOISEMAP           BOOL    FALSE           # Apply read noise map
 BIAS               BOOL    TRUE            # Bias subtraction
@@ -162,4 +162,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -186,4 +187,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -209,4 +211,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -236,4 +239,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -260,4 +264,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -283,4 +288,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -306,4 +312,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    FALSE           # Bias subtraction
   DARK               BOOL    FALSE           # Dark subtraction
@@ -329,4 +336,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -345,23 +353,24 @@
 # Dark subtraction only
 PPIMAGE_D          METADATA
-  BASE.FITS        BOOL    TRUE            # Save base detrended image?
-  BASE.MASK.FITS   BOOL    FALSE           # Save base detrended image?
-  BASE.VARIANCE.FITS BOOL    FALSE           # Save base detrended image?
-  CHIP.FITS        BOOL    FALSE           # Save chip-mosaic-ed image? 
-  CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
-  CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
-  OVERSCAN         BOOL    FALSE           # Overscan subtraction
-  BIAS             BOOL    FALSE           # Bias subtraction
-  DARK             BOOL    TRUE            # Dark subtraction
-  SHUTTER          BOOL    FALSE           # Shutter correction
-  FLAT             BOOL    FALSE           # Flat-field normalisation
-  MASK             BOOL    FALSE           # Mask bad pixels
-  MASK.BUILD       BOOL    FALSE	   # Build internal mask?
-  FRINGE           BOOL    FALSE           # Fringe subtraction
-  PHOTOM           BOOL    FALSE           # Source identification and photometry
-  ASTROM.CHIP      BOOL    FALSE           # Astrometry per chip?
-  ASTROM.MOSAIC    BOOL    FALSE           # Astrometry for mosaic?
-  BIN1.FITS        BOOL    TRUE            # Save 1st binned chip image?
-  BIN2.FITS        BOOL    TRUE            # Save 2nd binned chip image?
+  BASE.FITS          BOOL    TRUE            # Save base detrended image?
+  BASE.MASK.FITS     BOOL    FALSE           # Save base detrended image?
+  BASE.VARIANCE.FITS BOOL    FALSE           # Save base detrended image?
+  CHIP.FITS          BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.MASK.FITS     BOOL    FALSE           # Save chip-mosaic-ed image? 
+  CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
+  OVERSCAN           BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
+  BIAS               BOOL    FALSE           # Bias subtraction
+  DARK               BOOL    TRUE            # Dark subtraction
+  SHUTTER            BOOL    FALSE           # Shutter correction
+  FLAT               BOOL    FALSE           # Flat-field normalisation
+  MASK               BOOL    FALSE           # Mask bad pixels
+  MASK.BUILD         BOOL    FALSE	   # Build internal mask?
+  FRINGE             BOOL    FALSE           # Fringe subtraction
+  PHOTOM             BOOL    FALSE           # Source identification and photometry
+  ASTROM.CHIP        BOOL    FALSE           # Astrometry per chip?
+  ASTROM.MOSAIC      BOOL    FALSE           # Astrometry for mosaic?
+  BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
+  BIN2.FITS          BOOL    TRUE            # Save 2nd binned chip image?
 END
 
@@ -375,4 +384,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -398,4 +408,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -421,4 +432,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -444,4 +456,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -467,4 +480,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -490,4 +504,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -513,4 +528,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -536,4 +552,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -559,4 +576,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -589,4 +607,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -619,4 +638,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -642,4 +662,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -672,4 +693,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -695,4 +717,5 @@
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -729,4 +752,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -752,4 +776,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -775,4 +800,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -798,4 +824,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -827,4 +854,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -856,4 +884,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -879,4 +908,5 @@
   CHIP.VARIANCE.FITS BOOL    FALSE           # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -896,4 +926,5 @@
 PPIMAGE_JPEG       METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -916,4 +947,6 @@
   BIN1.JPEG        BOOL    TRUE            # Save 1st binned jpeg?
   BIN2.JPEG        BOOL    TRUE            # Save 2nd binned jpeg?
+  MASK.SATURATED   BOOL    FALSE           # DO NOT Mask the saturated pixels
+  MASK.LOW         BOOL    FALSE           # DO NOT Mask the saturated pixels
 END
 
@@ -921,4 +954,5 @@
 PPIMAGE_J1         METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -945,4 +979,6 @@
   BIN2.XBIN        S32     1               # Image is already binned
   BIN2.YBIN        S32     1               # Image is already binned
+  MASK.SATURATED   BOOL    FALSE           # DO NOT Mask the saturated pixels
+  MASK.LOW         BOOL    FALSE           # DO NOT Mask the saturated pixels
 END
 
@@ -950,4 +986,5 @@
 PPIMAGE_J2         METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -974,4 +1011,6 @@
   BIN2.XBIN        S32     1               # Image is already binned
   BIN2.YBIN        S32     1               # Image is already binned
+  MASK.SATURATED   BOOL    FALSE           # DO NOT Mask the saturated pixels
+  MASK.LOW         BOOL    FALSE           # DO NOT Mask the saturated pixels
 END
 
@@ -979,4 +1018,5 @@
 PPIMAGE_OA         METADATA
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -998,4 +1038,5 @@
 PPIMAGE_OP         METADATA
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN           BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1023,4 +1064,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1043,4 +1085,5 @@
 PPIMAGE_J1_RESID_B      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1079,4 +1122,5 @@
 PPIMAGE_J2_RESID_B        METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1115,4 +1159,5 @@
 PPIMAGE_J1_RESID_F      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1151,4 +1196,5 @@
 PPIMAGE_J2_RESID_F        METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1187,4 +1233,5 @@
 PPIMAGE_J1_RESID_R      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1223,4 +1270,5 @@
 PPIMAGE_J2_RESID_R        METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1260,4 +1308,5 @@
 PPIMAGE_J1_IMAGE_B      METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1296,4 +1345,5 @@
 PPIMAGE_J2_IMAGE_B        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1332,4 +1382,5 @@
 PPIMAGE_J1_IMAGE_F      METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1368,4 +1419,5 @@
 PPIMAGE_J2_IMAGE_F        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1404,4 +1456,5 @@
 PPIMAGE_J1_IMAGE_R      METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1440,4 +1493,5 @@
 PPIMAGE_J2_IMAGE_R        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1476,4 +1530,5 @@
 PPIMAGE_J1_IMAGE_M        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1512,4 +1567,5 @@
 PPIMAGE_J2_IMAGE_M        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1548,4 +1604,5 @@
 PPIMAGE_J1_RESID_M        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1584,4 +1641,5 @@
 PPIMAGE_J2_RESID_M        METADATA
   OVERSCAN        BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS            BOOL    FALSE           # Bias subtraction
   DARK            BOOL    FALSE           # Dark subtraction
@@ -1621,4 +1679,5 @@
 PPIMAGE_MOSAIC     METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1652,4 +1711,5 @@
 PPIMAGE_CHIPMOSAIC     METADATA
   OVERSCAN         BOOL    FALSE           # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    FALSE           # Dark subtraction
@@ -1688,6 +1748,6 @@
   CHIP.MASK.FITS   BOOL    FALSE           # Save chip-mosaic-ed image? 
   CHIP.VARIANCE.FITS BOOL  FALSE           # Save chip-mosaic-ed image? 
-  OVERSCAN         BOOL    FALSE           # Overscan subtraction
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Non-linearity correction; not implemented
   BIAS             BOOL    TRUE            # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1732,4 +1792,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -1762,4 +1823,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -1785,4 +1847,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN         BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS             BOOL    FALSE           # Bias subtraction
   DARK             BOOL    TRUE            # Dark subtraction
@@ -1813,4 +1876,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -1840,4 +1904,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
@@ -1865,4 +1930,5 @@
   CHIP.VARIANCE.FITS BOOL    TRUE            # Save chip-mosaic-ed image? 
   OVERSCAN           BOOL    TRUE            # Overscan subtraction
+  NONLIN             BOOL    FALSE           # Overscan subtraction
   BIAS               BOOL    TRUE            # Bias subtraction
   DARK               BOOL    TRUE            # Dark subtraction
Index: /branches/czw_branch/20101203/ippconfig/recipes/ppSub.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/ppSub.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/ppSub.config	(revision 30118)
@@ -72,4 +72,7 @@
 PHOTOMETRY	BOOL	FALSE		# Perform photometry?
 
+FORCED.PHOTOMETRY.BOTH BOOL FALSE       # forced photometry on input sources?
+FORCED.PHOTOMETRY.INPUT1 BOOL FALSE       # forced photometry on input sources?
+FORCED.PHOTOMETRY.INPUT2 BOOL FALSE       # forced photometry on input sources?
 
 # Recipe overrides for STACK
@@ -112,4 +115,13 @@
 	PHOTOMETRY	BOOL	TRUE	# Perform photometry?
 	CONVOLVE.TARGET STR     SINGLE2	# convolution direction
+END
+
+# Difference of warp - stack
+WARPSTACK_FORCED     METADATA
+	DUAL		BOOL	FALSE	# Dual convolution?
+	INVERSE		BOOL	FALSE   # Generate inverse subtraction?
+	PHOTOMETRY	BOOL	TRUE	# Perform photometry?
+	CONVOLVE.TARGET STR     SINGLE2	# convolution direction
+ FORCED.PHOTOMETRY.BOTH BOOL    TRUE    # forced photometry on input sources
 END
 
Index: /branches/czw_branch/20101203/ippconfig/recipes/psastro.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/psastro.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/psastro.config	(revision 30118)
@@ -238,2 +238,6 @@
 MOPS.TEST	METADATA
 END
+
+SAS_REFERENCE METADATA
+END
+
Index: /branches/czw_branch/20101203/ippconfig/recipes/psphot.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/psphot.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/psphot.config	(revision 30118)
@@ -49,4 +49,5 @@
 PEAKS_NMAX                          S32   5000            # on first pass, only keep NMAX peaks (0 == all)
 PEAKS_MIN_GAUSS                     F32   0.5             # On quick convolution, mask pixels for which the 
+PEAKS_POS2_NSIGMA_LIMIT             F32   25.0            # peak signficance threshold for POS2 sources. (ppSub)
 				    	  		  # input pixels contribute less than this fraction of the flux
 # parameters which adjust the footprint analysis
Index: /branches/czw_branch/20101203/ippconfig/recipes/reductionClasses.mdc
===================================================================
--- /branches/czw_branch/20101203/ippconfig/recipes/reductionClasses.mdc	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/recipes/reductionClasses.mdc	(revision 30118)
@@ -173,4 +173,12 @@
 WARPSTACK	METADATA
 	DIFF_PPSUB	STR	WARPSTACK
+	DIFF_PSPHOT	STR	DIFF
+	JPEG_BIN1	STR	PPIMAGE_J1
+	JPEG_BIN2	STR	PPIMAGE_J2
+END
+
+# reduction class specifically for warpstack diffs:
+WARPSTACK_FORCED	METADATA
+	DIFF_PPSUB	STR	WARPSTACK_FORCED
 	DIFF_PSPHOT	STR	DIFF
 	JPEG_BIN1	STR	PPIMAGE_J1
@@ -535,2 +543,19 @@
 END
 
+SAS_REFERENCE METADATA
+   CHIP_PPIMAGE    STR CHIP
+   CHIP_PSPHOT STR CHIP
+   WARP_PSWARP STR WARP
+   STACK_PPSTACK   STR STACK
+   STACK_PPSUB STR STACK
+   STACK_PSPHOT    STR STACK
+   DIFF_PPSUB  STR DIFF
+   DIFF_PSPHOT STR DIFF
+   JPEG_BIN1   STR PPIMAGE_J1
+   JPEG_BIN2   STR PPIMAGE_J2
+   FAKEPHOT    STR FAKEPHOT
+   ADDSTAR     STR ADDSTAR
+   PSASTRO     STR SAS_REFERENCE
+   STACKPHOT       STR     STACKPHOT
+END
+
Index: /branches/czw_branch/20101203/ippconfig/simtest/camera.config
===================================================================
--- /branches/czw_branch/20101203/ippconfig/simtest/camera.config	(revision 30117)
+++ /branches/czw_branch/20101203/ippconfig/simtest/camera.config	(revision 30118)
@@ -80,3 +80,4 @@
 
 # don't censor any masked pixels when making postage stamps
+# MASK.NO.CENSOR               U32 0xFFFFFFFF -- need to fix the MDC parser(s) to handle hex values
 MASK.NO.CENSOR               U32 4294967295
Index: /branches/czw_branch/20101203/pedestal/src/pedestal.c
===================================================================
--- /branches/czw_branch/20101203/pedestal/src/pedestal.c	(revision 30117)
+++ /branches/czw_branch/20101203/pedestal/src/pedestal.c	(revision 30118)
@@ -29,4 +29,5 @@
     psFitsMoveExtName(inFile, extname);
     psArray *cube = psFitsReadImageCube(inFile, psRegionSet(0, 0, 0, 0)); // Image cube
+    assert(cube);
     assert(cube->n == 2);               // We checked NAXIS3 earlier
 
Index: /branches/czw_branch/20101203/ppConfigDump/src/ppConfigDump.c
===================================================================
--- /branches/czw_branch/20101203/ppConfigDump/src/ppConfigDump.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppConfigDump/src/ppConfigDump.c	(revision 30118)
@@ -26,6 +26,7 @@
 void dump(const char *filename,     // Filename to which to dump
           const char *description,  // Description of what's being dumped
-          psMetadata *md            // Metadata to dump
-          )
+          psMetadata *md,           // Metadata to dump
+	  const char *compressMode
+    )
 {
     if (!filename || strlen(filename) == 0) {
@@ -38,9 +39,39 @@
             die(PS_EXIT_SYS_ERROR);
         }
-        fprintf(stdout, "%s", string);
+
+	if (compressMode) {
+	    if (strlen(compressMode) > 2) {
+		psErrorStackPrint(stderr, "invalid compression options %s!\n", compressMode);
+		die(PS_EXIT_CONFIG_ERROR);
+	    }
+	    char modeString[4];
+	    snprintf (modeString, 4, "w%s", compressMode);
+
+	    gzFile file = gzdopen (STDOUT_FILENO, modeString);
+	    if (file == Z_NULL) {
+		psErrorStackPrint(stderr, "Failed to open file\n");
+		die(PS_EXIT_SYS_ERROR);
+	    }
+	    int nbytes = gzwrite (file, string, strlen(string));
+	    if (nbytes != strlen(string)) {
+		psErrorStackPrint(stderr, "Failed to write contents of configuration file %s", filename);
+		psFree(string);
+		gzclose(file);
+		die(PS_EXIT_SYS_ERROR);
+	    }
+	    psFree(string);
+	    if (gzclose(file) != Z_OK) {
+		psErrorStackPrint(stderr, "Failed to close file, %s\n", filename);
+		die(PS_EXIT_SYS_ERROR);
+	    }
+	} else {
+	    fprintf(stdout, "%s", string);
+	}
         psFree(string);
-    } else if (!psMetadataConfigWrite(md, filename)) {
-        psErrorStackPrint(stderr, "Can't write %s to %s\n", description, filename);
-        die(PS_EXIT_SYS_ERROR);
+    } else {
+	if (!psMetadataConfigWrite(md, filename, compressMode)) {
+	    psErrorStackPrint(stderr, "Can't write %s to %s\n", description, filename);
+	    die(PS_EXIT_SYS_ERROR);
+	}
     }
 }
@@ -62,4 +93,6 @@
     arguments = psMetadataAlloc();
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-file", 0, "FITS file to use for camera determination", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-compress", 0, "output compression mode", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-z", 0, "default compression", false);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-dump-user", 0, "Filename for user configuration", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-dump-site", 0, "Filename for site configuration", NULL);
@@ -84,4 +117,11 @@
         psArgumentHelp(arguments);
         die(PS_EXIT_CONFIG_ERROR);
+    }
+
+    const char *defaultCompressMode = "7f";
+    const char *compressMode = psMetadataLookupStr(NULL, arguments, "-compress"); // compression
+    bool defaultCompression = psMetadataLookupBool(NULL, arguments, "-z"); // compression?
+    if (!compressMode && defaultCompression) {
+	compressMode = defaultCompressMode;
     }
 
@@ -122,20 +162,20 @@
 
     const char *userName = psMetadataLookupStr(NULL, arguments, "-dump-user"); // User filename
-    dump(userName, "user configuration", config->user);
+    dump(userName, "user configuration", config->user, compressMode);
 
     const char *siteName = psMetadataLookupStr(NULL, arguments, "-dump-site"); // Site filename
-    dump(siteName, "site configuration", config->site);
+    dump(siteName, "site configuration", config->site, compressMode);
 
     const char *systemName = psMetadataLookupStr(NULL, arguments, "-dump-system"); // System filename
-    dump(systemName, "system configuration", config->system);
+    dump(systemName, "system configuration", config->system, compressMode);
 
     const char *camName = psMetadataLookupStr(NULL, arguments, "-dump-camera"); // Camera filename
-    dump(camName, "camera configuration", config->camera);
+    dump(camName, "camera configuration", config->camera, compressMode);
 
     const char *formatName = psMetadataLookupStr(NULL, arguments, "-dump-format"); // Format filename
-    dump(formatName, "camera format", config->format);
+    dump(formatName, "camera format", config->format, compressMode);
 
     const char *recipesName = psMetadataLookupStr(NULL, arguments, "-dump-recipes"); // Recipes filename
-    dump(recipesName, "recipes", config->recipes);
+    dump(recipesName, "recipes", config->recipes, compressMode);
 
     recipeArgs = psMetadataLookupMetadata(NULL, arguments, "-dump-recipe");
@@ -148,5 +188,5 @@
         }
         const char *recipeFile = psMetadataLookupStr(NULL, recipeArgs, "filename"); // Filename for recipe
-        dump(recipeFile, "recipe", recipe);
+        dump(recipeFile, "recipe", recipe, compressMode);
     }
 
Index: /branches/czw_branch/20101203/ppImage/src/ppImageDetrendReadout.c
===================================================================
--- /branches/czw_branch/20101203/ppImage/src/ppImageDetrendReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppImage/src/ppImageDetrendReadout.c	(revision 30118)
@@ -62,5 +62,4 @@
     // Non-linearity correction
     if (options->doNonLin) {
-      //      linearity = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.LINEARITY");
       if (!ppImageDetrendNonLinear(input,detview,config)) {
 	psError(PS_ERR_UNKNOWN, false, "Unable to correct NonLinearity");
@@ -68,5 +67,4 @@
 	return(false);
       }
-      /*       ppImageDetrendNonLinear(detrend->input, input, options); */
     }
 
Index: /branches/czw_branch/20101203/ppImage/src/ppImageOptions.c
===================================================================
--- /branches/czw_branch/20101203/ppImage/src/ppImageOptions.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppImage/src/ppImageOptions.c	(revision 30118)
@@ -216,8 +216,8 @@
 
     // for these images, even if not required otherwise
-    options->doMaskBuild = psMetadataLookupBool(NULL, recipe, "MASK.BUILD");
-    options->doMaskSat   = psMetadataLookupBool(NULL, recipe, "MASK.SATURATED");
-    options->doMaskLow   = psMetadataLookupBool(NULL, recipe, "MASK.LOW");
-    options->doMaskBurntool = psMetadataLookupBool(NULL, recipe, "MASK.BURNTOOL");
+    options->doMaskBuild     = psMetadataLookupBool(NULL, recipe, "MASK.BUILD");
+    options->doMaskSat       = psMetadataLookupBool(NULL, recipe, "MASK.SATURATED");
+    options->doMaskLow       = psMetadataLookupBool(NULL, recipe, "MASK.LOW");
+    options->doMaskBurntool  = psMetadataLookupBool(NULL, recipe, "MASK.BURNTOOL");
     options->doVarianceBuild = psMetadataLookupBool(NULL, recipe, "VARIANCE.BUILD");
 
@@ -301,10 +301,31 @@
     options->checkCTE       = psMetadataLookupBool(NULL, recipe, "CHECK.CTE");
 
-    // even if not requested explicitly, if any of these are set, build an internal mask and variance:
-    if (options->doNoiseMap || options->doBias || options->doOverscan || options->doDark || options->doShutter || options->doFlat ||
-        options->doPhotom) {
+    /* doMaskBuild : there are some cases where we require a mask, so we force doMaskBuild to be set even if the user specified 'FALSE'
+     *
+     * doPhotom : a mask is required because it is used to mark the locations of stars
+     *
+     * doNoiseMap : no reason this needs to trigger a mask?
+     * doBias : no reason this needs to trigger a mask?
+     * doOverscan : no reason this needs to trigger a mask?
+     * doDark : no reason this needs to trigger a mask?
+     * doShutter : no reason this needs to trigger a mask?
+     * doFlat : no reason this needs to trigger a mask?
+     */
+
+    // if the variance image is requested, build it (if not supplied)
+    if (options->BaseVarianceFITS || options->ChipVarianceFITS) {
+        options->doVarianceBuild = true;
+    } 
+    // photometry and noisemap both require a variance image
+    if (options->doNoiseMap || options->doPhotom) {
+        options->doVarianceBuild = true;
+    } 
+
+    // we need a mask if we are going to apply these things:
+    if (options->doMaskSat || options->doMaskLow || options->doMaskBurntool || options->doMaskStats) {
         options->doMaskBuild = true;
-        options->doVarianceBuild = true;
-    } else if (options->doMask || options->doBG) {
+    }
+    // photometry, mask, and background all require a mask image
+    if (options->doMask || options->doBG || options->doPhotom) {
         options->doMaskBuild = true;
     }
Index: /branches/czw_branch/20101203/ppImage/src/ppImagePhotom.c
===================================================================
--- /branches/czw_branch/20101203/ppImage/src/ppImagePhotom.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppImage/src/ppImagePhotom.c	(revision 30118)
@@ -11,7 +11,7 @@
     pmCell *cell;
     pmReadout *readout;
-    printf("%x %s\n",psErrorCodeLast(),psErrorCodeString(psErrorCodeLast()));
+
     psphotInit();
-    printf("%x %s\n",psErrorCodeLast(),psErrorCodeString(psErrorCodeLast()));
+
     // find or define a pmFPAfile PSPHOT.INPUT
     pmFPAfile *input = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
@@ -20,10 +20,10 @@
         return false;
     }
-    printf("%x %s\n",psErrorCodeLast(),psErrorCodeString(psErrorCodeLast()));
+
     // we make a new copy of the output chip to keep psphot from modifying the output image
     pmChip *oldChip = pmFPAviewThisChip (view, input->src);
     pmChip *newChip = pmFPAviewThisChip (view, input->fpa);
     pmChipCopy (newChip, oldChip);
-    printf("%x %s\n",psErrorCodeLast(),psErrorCodeString(psErrorCodeLast()));
+
     // iterate over the cells and readout for this chip
     while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
@@ -34,7 +34,7 @@
         while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
             if (! readout->data_exists) { continue; }
-	    printf("%x %s\n",psErrorCodeLast(),psErrorCodeString(psErrorCodeLast()));
+
             // run the actual photometry analysis
-            if (!psphotReadout (config, view)) {
+            if (!psphotReadout (config, view, "PSPHOT.INPUT")) {
                 // This is likely a data quality issue
                 // XXX Split into multiple cases using error codes?
@@ -60,10 +60,4 @@
     ppImageMemoryDump("photom");
 
-    // the PSPHOT.INPUT file is a temporary file used to carry PPIMAGE.CHIP to psphotReadout
-    // XXX not sure that this is needed...
-//    pmFPAfileActivate (config->files, false, "PSPHOT.INPUT");
-
     return true;
 }
-
-// XXX do we need to deactivate all files and activate the psphot ones explicitly?
Index: /branches/czw_branch/20101203/ppImage/src/ppImageStatsOutput.c
===================================================================
--- /branches/czw_branch/20101203/ppImage/src/ppImageStatsOutput.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppImage/src/ppImageStatsOutput.c	(revision 30118)
@@ -28,5 +28,14 @@
         return false;
     }
-    if (!psMetadataConfigWrite(stats, resolved)) {
+
+    // check for Metadata compression options:
+    char *compressMode = NULL;
+    bool status = false;
+    if (config->camera) {
+	// XXX use a different config variable for this output?
+	compressMode = psMetadataLookupStr(&status, config->camera, "METADATA.COMPRESSION");
+    }
+
+    if (!psMetadataConfigWrite(stats, resolved, compressMode)) {
         psError(psErrorCodeLast(), false, "Unable to serialize stats metadata.\n");
         psFree(resolved);
Index: /branches/czw_branch/20101203/ppStack/src/ppStackPhotometry.c
===================================================================
--- /branches/czw_branch/20101203/ppStack/src/ppStackPhotometry.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppStack/src/ppStackPhotometry.c	(revision 30118)
@@ -54,8 +54,6 @@
     psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask
     psImageMaskType markValue = pmConfigMaskGet("MARK.VALUE", config); // Bits to use for marking
-    psMetadataAddImageMask(psphot, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE,
-                            "Bits to mask", maskValue);
-    psMetadataAddImageMask(psphot, PS_LIST_TAIL, "MARK.PSPHOT", PS_META_REPLACE,
-                           "Bits to use for mark", markValue);
+    psMetadataAddImageMask(psphot, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "Bits to mask", maskValue);
+    psMetadataAddImageMask(psphot, PS_LIST_TAIL, "MARK.PSPHOT", PS_META_REPLACE, "Bits to use for mark", markValue);
 
     psArray *inSources = options->sources;
@@ -67,5 +65,5 @@
 
     pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
-    if (!psphotReadoutKnownSources(config, photView, inSources)) {
+    if (!psphotReadoutKnownSources(config, photView, "PSPHOT.INPUT", inSources)) {
         // This is likely a data quality issue
         // XXX Split into multiple cases using error codes?
Index: /branches/czw_branch/20101203/ppSub/doc/psphot.txt
===================================================================
--- /branches/czw_branch/20101203/ppSub/doc/psphot.txt	(revision 30118)
+++ /branches/czw_branch/20101203/ppSub/doc/psphot.txt	(revision 30118)
@@ -0,0 +1,36 @@
+
+Notes on psphot function calls within ppsub:
+
+we have these psphotReadout varients:
+
+* psphotReadout : ppImagePhotom.c, ppSimPhotom*, 
+* psphotReadoutFindPSF : used by ppSubMatchPSFs.c, ppSubMakePSF.c, pswarpLoop.c
+* psphotReadoutKnownSources : used by ppStackPhotometry.c 
+* psphotReadoutMinimal : used by ppSubReadoutPhotometry.c
+
+* psphotStackReadout : used only by psphotStack.c
+* psphotForcedReadout : used only by psphotForced.c
+* psphotMakePSFReadout : used only by psphotMakePSF.c
+
+psphotReadout:
+  * operates on pmFPAfile "PSPHOT.INPUT" -> convert to an input argument (filerule)
+  * expects a readout at the current view, populated with a image (can create mask and variance)
+  * XXX what about the headers?
+
+  * adds a photcode to readout->analysis
+  * creates a mask and optionally modifies the variance (NOTE!)
+  * if needed, generates PSPHOT.BACKMDL & PSPHOT.BACKMDL.STDEV pmFPAfiles (internal)
+  * optionally copies PSF model from PSPHOT.PSF.LOAD to PSPHOT.INPUT
+  * detetections / sources saved on readout->analysis as PSPHOT.DETECTIONS
+  * result psf goes on readout->analyss as PSPHOT.PSF
+  * detection efficiency data goes on readout->analyss as DETEFF
+  * copy input sources from PSPHOT.SOURCES.CMF & PSPHOT.SOURCES.TXT -> PSPHOT.DETECTIONS
+  * header data goes into PSPHOT.HEADER
+  * psf clump stuff goes on readout->analysis
+
+
+
+---
+
+in ppSubMatchPSFs.c : we call psphotReadoutFindPSF to measure the PSF using sources already loaded
+  (PPSUB.INPUT & PPSUB.REF)
Index: /branches/czw_branch/20101203/ppSub/src/Makefile.am
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/Makefile.am	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/Makefile.am	(revision 30118)
@@ -38,4 +38,5 @@
 	ppSubLoop.c			\
 	ppSubDefineOutput.c		\
+	ppSubInputDetections.c		\
 	ppSubExtras.c			\
 	ppSubFlagNeighbors.c		\
@@ -46,4 +47,5 @@
 	ppSubReadoutJpeg.c		\
 	ppSubReadoutPhotometry.c	\
+	ppSubReadoutForcedPhot.c	\
 	ppSubReadoutStats.c		\
 	ppSubReadoutSubtract.c		\
Index: /branches/czw_branch/20101203/ppSub/src/ppSub.h
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSub.h	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSub.h	(revision 30118)
@@ -45,4 +45,6 @@
     bool photometry;                    // Perform photometry?
     bool inverse;                       // Output inverse subtraction as well?
+    bool forcedPhot1;                   // perform forced photometry?
+    bool forcedPhot2;                   // perform forced photometry?
     bool saveInConv;                    // Save convolved input?
     bool saveRefConv;                   // Save convolved reference?
@@ -105,4 +107,8 @@
                             ppSubData *data ///< Processing data
     );
+
+bool ppSubInputDetections (bool *foundDetections, const char *sourcesName, const char *imageName, ppSubData *data);
+bool ppSubReadoutForcedPhot(const char *outputName, const char *targetName, const char *sourceName, ppSubData *data);
+bool psphotCopyResults (bool *foundDetections, pmFPAfile *target, pmFPAfile *source, pmFPAview *view);
 
 /// Higher-order background subtraction
Index: /branches/czw_branch/20101203/ppSub/src/ppSubArguments.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubArguments.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubArguments.c	(revision 30118)
@@ -86,4 +86,7 @@
     psMetadataAddS32(arguments, PS_LIST_TAIL, "-convolve", 0, "Image to convolve [1 or 2]", 0);
     psMetadataAddBool(arguments, PS_LIST_TAIL, "-photometry", 0, "Perform photometry?", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-forced-phot", 0, "Perform forced photometry?", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-forced-input1", 0, "Perform forced photometry?", NULL);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-forced-input2", 0, "Perform forced photometry?", NULL);
     psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp", 0, "Zero point for photometry", NAN);
     psMetadataAddBool(arguments, PS_LIST_TAIL, "-inverse", 0, "Generate inverse subtractions?", false);
Index: /branches/czw_branch/20101203/ppSub/src/ppSubBackground.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubBackground.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubBackground.c	(revision 30118)
@@ -37,26 +37,22 @@
     pmFPAview *view = ppSubViewReadout(); // View to readout
     pmReadout *outRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT"); // Output image
-    pmReadout *modelRO = pmFPAfileThisReadout(config->files, view, "PSPHOT.BACKMDL"); // Background model
 
-    // Generate the background model, if required
+    // Generate the background model
+    if (!psphotModelBackground(config, view, "PPSUB.OUTPUT")) {
+      psError(psErrorCodeLast(), false, "Unable to model background");
+      psFree(view);
+      return false;
+    }
+
+    // select the model readout (should now exist)
+    pmReadout *modelRO = pmFPAfileThisReadout(config->files, view, "PSPHOT.BACKMDL");
     if (!modelRO) {
-        // Create the background model
-        if (!psphotModelBackgroundReadoutFileIndex(config, view, "PPSUB.OUTPUT", 0)) {
-            psError(psErrorCodeLast(), false, "Unable to model background");
-            psFree(view);
-            return false;
-        }
-        // select the model readout (should now exist)
-        modelRO = pmFPAfileThisReadout(config->files, view, "PSPHOT.BACKMDL");
-        if (!modelRO) {
-            psError(psErrorCodeLast(), false, "Unable to find background model");
-            psFree(view);
-            return false;
-        }
+      psError(psErrorCodeLast(), false, "Unable to find background model");
+      psFree(view);
+      return false;
     }
     psFree(view);
 
-    psImageBinning *binning = psMetadataLookupPtr(&mdok, modelRO->analysis,
-                                                  "PSPHOT.BACKGROUND.BINNING"); // Binning for model
+    psImageBinning *binning = psMetadataLookupPtr(&mdok, modelRO->analysis, "PSPHOT.BACKGROUND.BINNING"); // Binning for model
     psImage *modelImage = modelRO->image; // Background model
     psImage *image = outRO->image; // Image of interest
@@ -83,7 +79,4 @@
     }
 
-    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL");
-    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL.STDEV");
-
     return true;
 }
Index: /branches/czw_branch/20101203/ppSub/src/ppSubCamera.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubCamera.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubCamera.c	(revision 30118)
@@ -221,7 +221,18 @@
                           "Generate inverse subtractions?", true);
     }
-
-    data->inverse = psMetadataLookupBool(NULL, recipe, "INVERSE");
-    data->photometry = psMetadataLookupBool(NULL, recipe, "PHOTOMETRY");
+    if (psMetadataLookupBool(NULL, config->arguments, "-forced-phot")) {
+        psMetadataAddBool(recipe, PS_LIST_TAIL, "FORCED.PHOTOMETRY.BOTH", PS_META_REPLACE, "Perform forced photometry?", true);
+    }
+    if (psMetadataLookupBool(NULL, config->arguments, "-forced-input1")) {
+        psMetadataAddBool(recipe, PS_LIST_TAIL, "FORCED.PHOTOMETRY.INPUT1", PS_META_REPLACE, "Perform forced photometry?", true);
+    }
+    if (psMetadataLookupBool(NULL, config->arguments, "-forced-input2")) {
+        psMetadataAddBool(recipe, PS_LIST_TAIL, "FORCED.PHOTOMETRY.INPUT2", PS_META_REPLACE, "Perform forced photometry?", true);
+    }
+
+    data->inverse     = psMetadataLookupBool(NULL, recipe, "INVERSE");
+    data->photometry  = psMetadataLookupBool(NULL, recipe, "PHOTOMETRY");
+    data->forcedPhot1 = psMetadataLookupBool(NULL, recipe, "FORCED.PHOTOMETRY.BOTH") || psMetadataLookupBool(NULL, recipe, "FORCED.PHOTOMETRY.INPUT1");
+    data->forcedPhot2 = psMetadataLookupBool(NULL, recipe, "FORCED.PHOTOMETRY.BOTH") || psMetadataLookupBool(NULL, recipe, "FORCED.PHOTOMETRY.INPUT2");
 
     // Convolved input image
@@ -363,6 +374,4 @@
             return false;
         }
-        // specify the number of psphot input images
-        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
         pmFPAfileActivate(config->files, false, "PSPHOT.INPUT");
 
@@ -405,4 +414,41 @@
             invSources->save = true;
         }
+
+	// files need to do the forced photometry on the positions of sources in the positive images
+        if (data->forcedPhot1) {
+	    // this pmFPAfile is used to carry sources detected in the positive image #1
+            pmFPAfile *posSources1 = defineOutputFile(config, input, true, "PPSUB.POS1.SOURCES", PM_FPA_FILE_CMF);
+            if (!posSources1) {
+                psError(psErrorCodeLast(), false, "Unable to set up forced source file.");
+                return false;
+            }
+            posSources1->save = true;
+
+	    // this pmFPAfile is used to carry sources detected in the diff image @ the positions from positive image #1
+            pmFPAfile *frcSources1 = defineOutputFile(config, input, true, "PPSUB.FORCED1.SOURCES", PM_FPA_FILE_CMF);
+            if (!frcSources1) {
+                psError(psErrorCodeLast(), false, "Unable to set up forced source file.");
+                return false;
+            }
+            frcSources1->save = true;
+	}
+
+        if (data->forcedPhot2) {
+	    // this pmFPAfile is used to carry sources detected in the positive image #2
+            pmFPAfile *posSources2 = defineOutputFile(config, ref, true, "PPSUB.POS2.SOURCES", PM_FPA_FILE_CMF);
+            if (!posSources2) {
+                psError(psErrorCodeLast(), false, "Unable to set up forced source file.");
+                return false;
+            }
+            posSources2->save = true;
+
+	    // this pmFPAfile is used to carry sources detected in the diff image @ the positions from positive image #2
+            pmFPAfile *frcSources2 = defineOutputFile(config, ref, true, "PPSUB.FORCED2.SOURCES", PM_FPA_FILE_CMF);
+            if (!frcSources2) {
+                psError(psErrorCodeLast(), false, "Unable to set up forced source file.");
+                return false;
+            }
+            frcSources2->save = true;
+        }
     }
 
Index: /branches/czw_branch/20101203/ppSub/src/ppSubFlagNeighbors.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubFlagNeighbors.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubFlagNeighbors.c	(revision 30118)
@@ -235,5 +235,5 @@
 	src = sources->data[Imin]; 
 
-	fprintf (stderr, "j: %d, Imin: %d, obj x,y: %f, %f  src x,y: %f, %f, SN: %f, ID: %d\n", j, Imin, obj->x, obj->y, src->peak->xf, src->peak->yf, src->peak->SN, src->id);
+	// fprintf (stderr, "j: %d, Imin: %d, obj x,y: %f, %f  src x,y: %f, %f, SN: %f, ID: %d\n", j, Imin, obj->x, obj->y, src->peak->xf, src->peak->yf, src->peak->SN, src->id);
 
 	// add source to object
Index: /branches/czw_branch/20101203/ppSub/src/ppSubInputDetections.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubInputDetections.c	(revision 30118)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubInputDetections.c	(revision 30118)
@@ -0,0 +1,190 @@
+/** @file ppSubInputDetections.c
+ *
+ *  @ingroup ppSub
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-18 00:31:20 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psphot.h>
+
+#include "ppSub.h"
+
+pmHDU *getHDUandLevel (pmFPALevel *level, pmFPA *fpa, pmFPAview *view) {
+
+    pmHDU *hdu = NULL;
+    *level = PM_FPA_LEVEL_NONE;
+
+    pmCell *cell = pmFPAviewThisCell(view, fpa);
+    if (cell) {
+	hdu = cell->hdu; // cell
+	if (hdu) {
+	    *level = PM_FPA_LEVEL_CELL;
+	    return hdu;
+	}
+    }
+
+    pmChip *chip = pmFPAviewThisChip(view, fpa);
+    if (chip) {
+	hdu = chip->hdu; // chip
+	if (hdu) {
+	    *level = PM_FPA_LEVEL_CHIP;
+	    return hdu;
+	}
+    }
+
+    hdu = fpa->hdu; // fpa
+    if (hdu) {
+	*level = PM_FPA_LEVEL_FPA;
+	return hdu;
+    }
+    return NULL;
+}      
+
+pmHDU *setHDUatLevel (pmFPALevel level, pmFPA *fpa, pmFPAview *view, char *extname) {
+
+    switch (level) {
+      case (PM_FPA_LEVEL_FPA): {
+	  if (!fpa->hdu) {
+	      fpa->hdu = pmHDUAlloc(extname);
+	  }
+	  return fpa->hdu;
+      }
+      case (PM_FPA_LEVEL_CHIP): {
+	  pmChip *chip = pmFPAviewThisChip(view, fpa);
+	  if (!chip->hdu) {
+	      chip->hdu = pmHDUAlloc(extname);
+	  }
+	  return chip->hdu;
+      }
+      case (PM_FPA_LEVEL_CELL): {
+	  pmCell *cell = pmFPAviewThisCell(view, fpa);
+	  if (!cell->hdu) {
+	      cell->hdu = pmHDUAlloc(extname);
+	  }
+	  return cell->hdu;
+      }
+      default:
+	return NULL;
+    }
+    return NULL;
+}      
+
+bool ppSubInputDetections (bool *foundDetections, const char *sourcesName, const char *imageName, ppSubData *data) {
+
+    bool mdok = false;
+
+    psAssert(data, "Require processing data");
+    pmConfig *config = data->config;    // Configuration
+    psAssert(config, "Require configuration");
+
+    // select the view of interest
+    pmFPAview *view = ppSubViewReadout(); // View to readout
+
+    // point PSPHOT.INPUT at the positive image
+    pmFPAfile *imageFile   = psMetadataLookupPtr(&mdok, config->files, imageName); // Image to photometer
+    pmFPAfile *sourcesFile = psMetadataLookupPtr(&mdok, config->files, sourcesName); // Place results her
+    pmFPAfile *photFile    = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.INPUT"); // holder for the working image
+
+    // create a psphot working file, so we don't damage the image or affect existing sources
+    if (!pmFPACopy(photFile->fpa, imageFile->fpa)) {
+	psError(PPSUB_ERR_CONFIG, false, "Unable to copy FPA for photometry");
+	psFree(view);
+	return false;
+    }
+
+    pmFPALevel hduLevel = PM_FPA_LEVEL_NONE;
+    pmHDU *imageHDU = getHDUandLevel (&hduLevel, imageFile->fpa, view);
+
+    if (imageHDU) {
+	pmFPALevel outLevel = PM_FPA_LEVEL_NONE;
+	pmHDU *sourcesHDU = getHDUandLevel (&outLevel, sourcesFile->fpa, view);
+	if (!sourcesHDU) {
+	    sourcesHDU = setHDUatLevel (hduLevel, sourcesFile->fpa, view, imageHDU->extname);
+	}
+	
+	if (!sourcesHDU->header) {
+	    sourcesHDU->header = psMetadataAlloc();
+	}
+	if (!psMetadataCopy(sourcesHDU->header, imageHDU->header)) {
+	    psError(PPSUB_ERR_PROG, false, "Unable to copy header");
+	    return false;
+	}
+    }
+
+    if (!psphotReadout(config, view, "PSPHOT.INPUT")) {
+	psErrorStackPrint(stderr, "Unable to perform photometry on image");
+	psWarning("Unable to perform photometry on image --- suspect bad data quality.");
+	ppSubDataQuality(data, psErrorCodeLast(), PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
+    }
+    // save the outputs on PPSUB.POS1.SOURCES
+    if (!psphotCopyResults (foundDetections, sourcesFile, photFile, view)) {
+	psError(PPSUB_ERR_PROG, false, "Unable to copy psphot outputs");
+	return false;
+    }
+    // if no sources were found here, we report that back and let them handle it
+
+    return true;
+}
+
+bool psphotCopyResults (bool *foundDetections, pmFPAfile *target, pmFPAfile *source, pmFPAview *view) {
+
+    pmReadout *sourceRO = pmFPAviewThisReadout(view, source->fpa);
+    psAssert(sourceRO, "programming error: source readout not defined");
+
+    pmReadout *targetRO = pmFPAviewThisReadout(view, target->fpa);
+    if (!targetRO) {
+	pmCell *targetCell = pmFPAviewThisCell(view, target->fpa);
+	targetRO = pmReadoutAlloc(targetCell);
+	psAssert(targetRO, "programming error: could not make target readout");
+    }
+
+    // If no sources were found, there's no error, but we need to inform the calling function
+    pmDetections *detections = psMetadataLookupPtr(NULL, sourceRO->analysis, "PSPHOT.DETECTIONS"); // Sources
+    if (!detections) {
+	*foundDetections = false;
+	return true;
+    } else {
+	*foundDetections = true;
+    }
+
+    psArray *sources = detections->allSources; 
+    psAssert (sources, "missing sources?");
+
+    if (!psMetadataCopySingle(targetRO->analysis, sourceRO->analysis, "PSPHOT.DETECTIONS")) {
+	psError(PPSUB_ERR_PROG, false, "Unable to copy PSPHOT.DETECTIONS");
+	return false;
+    }
+    if (!psMetadataCopySingle(targetRO->analysis, sourceRO->analysis, "PSPHOT.HEADER")) {
+	psError(PPSUB_ERR_PROG, false, "Unable to copy PSPHOT.HEADER");
+	return false;
+    }
+    if (!psMetadataCopySingle(targetRO->analysis, sourceRO->analysis, PM_DETEFF_ANALYSIS)) {
+	psError(PPSUB_ERR_PROG, false, "Unable to copy Detection Efficiency");
+	return false;
+    }
+
+    // Ensure photometry information is put in the header
+    // XXX create one if it does not exist?
+    pmHDU *hdu = pmHDUFromReadout(targetRO); // HDU for readout
+    if (hdu) {
+	psMetadata *header = psMetadataLookupMetadata(NULL, targetRO->analysis, "PSPHOT.HEADER"); // Header
+	hdu->header = psMetadataCopy(hdu->header, header);
+    }
+
+    targetRO->data_exists = true;
+    targetRO->parent->data_exists = true;
+    targetRO->parent->parent->data_exists = true;
+
+    return true;
+}
+
Index: /branches/czw_branch/20101203/ppSub/src/ppSubLoop.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubLoop.c	(revision 30118)
@@ -36,4 +36,6 @@
     psAssert(config, "Require configuration.");
 
+    bool success = true;
+
     pmConfigCamerasCull(config, NULL);
     pmConfigRecipesCull(config, "PPSUB,PPSTATS,PSPHOT,PSASTRO,MASKS,JPEG");
@@ -57,17 +59,70 @@
     }
 
+    if (data->forcedPhot1) {
+	bool foundDetections = false;
+	if (!ppSubInputDetections(&foundDetections, "PPSUB.POS1.SOURCES", "PPSUB.INPUT", data)) {
+	    psError(psErrorCodeLast(), false, "Unable to measure positive detections (1)");
+	    success = false;
+            goto ESCAPE;
+	}
+	// if nothing was found, don't bother doing the forced photometry below
+	if (!foundDetections) {
+	    psWarning ("no sources found in positive image 1, skipping forced photometry");
+	    data->forcedPhot1 = false;
+	}
+    }
+    if (data->forcedPhot2) {
+        // Change the recipe to use a higher nsigma limit and quit after pass1
+        psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
+
+        psF32 nsigma_peak_save = psMetadataLookupF32 (NULL, recipe, "PEAKS_NSIGMA_LIMIT");
+        char *breakPt_save =  psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
+
+        bool mdok;
+        psF32 pos2_nsigma_peak = psMetadataLookupF32 (&mdok, recipe, "PEAKS_POS2_NSIGMA_LIMIT");
+        if (!mdok) {
+            psWarning("PEAKS_POS2_NSIGMA_LIMIT not found in recipe. Will use 25.\n");
+            pos2_nsigma_peak = 25.;
+        }
+        psMetadataAddF32(recipe, PS_LIST_TAIL, "PEAKS_NSIGMA_LIMIT", PS_META_REPLACE, "", pos2_nsigma_peak);
+        psMetadataAddStr(recipe, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", "PASS1");
+
+	bool foundDetections = false;
+	if (!ppSubInputDetections(&foundDetections, "PPSUB.POS2.SOURCES", "PPSUB.REF", data)) {
+	    psError(psErrorCodeLast(), false, "Unable to measure positive detections (2)");
+            psMetadataAddF32(recipe, PS_LIST_TAIL, "PEAKS_NSIGMA_LIMIT", PS_META_REPLACE, "", nsigma_peak_save);
+            psMetadataAddStr(recipe, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", breakPt_save);
+	    success = false;
+            goto ESCAPE;
+	}
+        psMetadataAddF32(recipe, PS_LIST_TAIL, "PEAKS_NSIGMA_LIMIT", PS_META_REPLACE, "", nsigma_peak_save);
+        psMetadataAddStr(recipe, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", breakPt_save);
+	// if nothing was found, don't bother doing the forced photometry below
+	if (!foundDetections) {
+	    psWarning ("no sources found in positive image 2, skipping forced photometry");
+	    data->forcedPhot2 = false;
+	}
+    }
+
+    // XXX if it exists, use the POS1, POS2 successs for the FWHMs
     if (!ppSubMatchPSFs(data)) {
         psError(psErrorCodeLast(), false, "Unable to match PSFs.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     if (data->quality) {
         // Can't do anything at all
-        return true;
+        success = false;
+        goto ESCAPE;
     }
     // generate the residual stamp grid for visualization
     if (!ppSubResidualSampleJpeg(config)) {
         psError(psErrorCodeLast(), false, "Unable to update.");
-        return false;
-    }
+        success = false;
+        goto ESCAPE;
+    }
+
+    // XXX add in a positive image detection step here (if needed)
+    
 
     psMetadataAddF32(data->stats, PS_LIST_TAIL, "TIME_MATCH", 0, "Time to match PSFs",
@@ -77,10 +132,12 @@
     if (!ppSubFilesIterateUp(config, PPSUB_FILES_INPUT)) {
         psError(PPSUB_ERR_IO, false, "Unable to close input files.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
     if (!ppSubLowThreshold(data)) {
         psError(psErrorCodeLast(), false, "Unable to threshold images.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
@@ -88,15 +145,18 @@
     if (!ppSubFilesIterateDown(config, PPSUB_FILES_SUB)) {
         psError(PPSUB_ERR_IO, false, "Unable to set up subtraction files.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
     if (!ppSubDefineOutput("PPSUB.OUTPUT", config)) {
         psError(psErrorCodeLast(), false, "Unable to define output.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
     if (!data->quality && !ppSubMakePSF(data)) {
         psError(psErrorCodeLast(), false, "Unable to generate PSF.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
@@ -113,5 +173,6 @@
     if (!ppSubReadoutSubtract(config)) {
         psError(psErrorCodeLast(), false, "Unable to subtract images.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // dumpout(config, "diff.1.fits");
@@ -120,5 +181,6 @@
     if (!ppSubFilesIterateUp(config, PPSUB_FILES_PSF | PPSUB_FILES_CONV)) {
         psError(PPSUB_ERR_IO, false, "Unable to close input files.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // dumpout(config, "diff.2a.fits");
@@ -127,5 +189,6 @@
     if (!ppSubBackground(config)) {
         psError(psErrorCodeLast(), false, "Unable to subtract background.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // dumpout(config, "diff.2b.fits");
@@ -134,5 +197,6 @@
     if (!ppSubVarianceRescale(config, data)) {
         psError(psErrorCodeLast(), false, "Unable to rescale variance.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // dumpout(config, "diff.2c.fits");
@@ -140,21 +204,43 @@
     if (data->quality) {
         // Done all we can do up to this point
-        return true;
+        success = false;
+        goto ESCAPE;
     }
 
     if (!ppSubFilesIterateDown(config, PPSUB_FILES_PHOT_SUB)) {
         psError(PPSUB_ERR_IO, false, "Unable to set up photometry files.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
     if (!data->quality && !ppSubReadoutPhotometry("PPSUB.OUTPUT", data)) {
         psError(psErrorCodeLast(), false, "Unable to perform photometry.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // dumpout(config, "diff.3.fits");
+
+    // forced photometry for positive image 1
+    if (data->forcedPhot1 && !data->quality) {
+	if (!ppSubReadoutForcedPhot("PPSUB.FORCED1.SOURCES", "PPSUB.OUTPUT", "PPSUB.POS1.SOURCES", data)) {
+	    psError(psErrorCodeLast(), false, "Unable to perform photometry.");
+	    success = false;
+            goto ESCAPE;
+	}
+    }
+
+    // forced photometry for positive image 2
+    if (data->forcedPhot2 && !data->quality) {
+	if (!ppSubReadoutForcedPhot("PPSUB.FORCED2.SOURCES", "PPSUB.OUTPUT", "PPSUB.POS2.SOURCES", data)) {
+	    psError(psErrorCodeLast(), false, "Unable to perform photometry.");
+	    success = false;
+            goto ESCAPE;
+	}
+    }
 
     if (!ppSubFilesIterateUp(config, PPSUB_FILES_PHOT_SUB)) {
         psError(PPSUB_ERR_IO, false, "Unable to set up photometry files.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
@@ -162,5 +248,6 @@
     if (!ppSubReadoutStats(data)) {
         psError(psErrorCodeLast(), false, "Unable to collect statistics");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
     // Do Mask Stats
@@ -169,5 +256,6 @@
       if (!ppSubMaskStats(config, view,data->stats)) {
 	psError(psErrorCodeLast(), false, "Unable to generate mask statistics");
-	return(false);
+	success = false;
+        goto ESCAPE;
       }
     }
@@ -177,5 +265,6 @@
     if (!ppSubReadoutJpeg(config)) {
         psError(psErrorCodeLast(), false, "Unable to update.");
-        return false;
+        success = false;
+        goto ESCAPE;
     }
 
@@ -184,15 +273,18 @@
         if (!ppSubFilesIterateDown(config, PPSUB_FILES_INV)) {
             psError(PPSUB_ERR_IO, false, "Unable to set up inverse files.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
         if (data->inverse && !ppSubDefineOutput("PPSUB.INVERSE", config)) {
             psError(psErrorCodeLast(), false, "Unable to define inverse.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
         if (!ppSubReadoutInverse(config)) {
             psError(psErrorCodeLast(), false, "Unable to invert images.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
@@ -200,15 +292,18 @@
         if (!ppSubFilesIterateUp(config, PPSUB_FILES_SUB)) {
             psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
         if (!ppSubFilesIterateDown(config, PPSUB_FILES_PHOT_INV)) {
             psError(PPSUB_ERR_IO, false, "Unable to set up inverse files.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
         if (!data->quality && !ppSubReadoutPhotometry("PPSUB.INVERSE", data)) {
             psError(psErrorCodeLast(), false, "Unable to perform photometry.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
 
@@ -216,5 +311,6 @@
         if (!ppSubFilesIterateUp(config, PPSUB_FILES_INV | PPSUB_FILES_PHOT_INV)) {
             psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
-            return false;
+            success = false;
+            goto ESCAPE;
         }
     } else {
@@ -223,8 +319,14 @@
         if (!ppSubFilesIterateUp(config, PPSUB_FILES_SUB)) {
             psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
-            return false;
-        }
-    }
-
-    return true;
+            success = false;
+            goto ESCAPE;
+        }
+    }
+
+ESCAPE:
+    pmFPAfileDropInternal(config->files, "PSPHOT.BACKGND");
+    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL");
+    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL.STDEV");
+
+    return success;
 }
Index: /branches/czw_branch/20101203/ppSub/src/ppSubMakePSF.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubMakePSF.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubMakePSF.c	(revision 30118)
@@ -35,11 +35,4 @@
 
     psTimerStart("PPSUB_PHOT");
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSub
-    psAssert(recipe, "We checked this earlier, so it should be here.");
-
-    if (!psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
-        return true;
-    }
 
     bool reverse = psMetadataLookupBool(NULL, config->arguments, "REVERSE"); // Reverse sense of subtraction?
@@ -93,5 +86,5 @@
     // use flags to toss totally bogus entries?
     psArray *goodSources = ppSubSelectPSFSources (sources);
-    if (!psphotReadoutFindPSF(config, view, goodSources)) {
+    if (!psphotReadoutFindPSF(config, view, "PSPHOT.INPUT", goodSources)) {
         // This is likely a data quality issue
         // XXX Split into multiple cases using error codes?
Index: /branches/czw_branch/20101203/ppSub/src/ppSubMatchPSFs.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubMatchPSFs.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubMatchPSFs.c	(revision 30118)
@@ -72,5 +72,5 @@
     // Extract the loaded sources from the associated readout, and generate PSF
     // Here, we assume the image is background-subtracted
-    if (!psphotReadoutFindPSF(config, view, sources)) {
+    if (!psphotReadoutFindPSF(config, view, "PSPHOT.INPUT", sources)) {
         psErrorStackPrint(stderr, "Unable to determine PSF");
         psWarning("Unable to determine PSF.");
Index: /branches/czw_branch/20101203/ppSub/src/ppSubReadoutForcedPhot.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubReadoutForcedPhot.c	(revision 30118)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubReadoutForcedPhot.c	(revision 30118)
@@ -0,0 +1,100 @@
+/** @file ppSubReadoutForcedphot.c
+ *
+ *  @brief
+ *
+ *  @ingroup ppSub
+ *
+ *  @author IfA
+ *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-18 00:31:20 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psphot.h>
+
+#include "ppSub.h"
+
+// run forced photometry on the image in 'targetName' at the positions of the sources in 'sourceName'
+// this function is only called if (data->forcedPhot1 || data->forcedPhot2) (ppSubLoop.c:186,194)
+bool ppSubReadoutForcedPhot(const char *outputName, const char *targetName, const char *sourceName, ppSubData *data)
+{
+    bool foundDetections = false;
+    bool mdok = false;
+
+    psAssert(data, "Require processing data");
+    pmConfig *config = data->config;    // Configuration
+    psAssert(config, "Require configuration");
+
+    // select the view of interest
+    pmFPAview *view = ppSubViewReadout(); // View to readout
+
+    pmFPAfile *sourceFile = psMetadataLookupPtr(&mdok, config->files, sourceName); // positive image sources
+    pmFPAfile *targetFile = psMetadataLookupPtr(&mdok, config->files, targetName); // diff image pixels
+    pmFPAfile *outputFile = psMetadataLookupPtr(&mdok, config->files, outputName); // result file
+
+    psAssert (sourceFile, "failed to construct sourceName %s", sourceName);
+    psAssert (targetFile, "failed to construct targetName %s", targetName);
+    psAssert (outputFile, "failed to construct outputName %s", outputName);
+
+    // copy the image data to PSPHOT.INPUT so that psphotReadoutForcedKnownSources does
+    // not affect the prior results on targetName (ie, diff detections)
+    pmFPAfile *photFile = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.INPUT"); // Photometry file
+    if (!pmFPACopy(photFile->fpa, targetFile->fpa)) {
+        psError(PPSUB_ERR_CONFIG, false, "Unable to copy FPA for photometry");
+        psFree(view);
+        return false;
+    }
+
+    // select the reference position sources from sourceName
+    pmReadout *sourceRO = pmFPAviewThisReadout(view, sourceFile->fpa);
+    psAssert(sourceRO, "programming error: source readout not defined");
+
+    pmDetections *sourceDet = psMetadataLookupPtr(NULL, sourceRO->analysis, "PSPHOT.DETECTIONS"); // Sources
+    if (!sourceDet) {
+	// XXX remove the pixels from photFile?
+	// XXX other cleanup operations?
+	return true;
+    }
+    psArray *sources = sourceDet->allSources;
+    psAssert (sources, "missing sources?");
+
+    // grab the PSF information from the pmFPAfile PSPHOT.PSF.LOAD
+    pmFPAfile *psfFile = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.PSF.LOAD"); // PSF file
+    ppSubCopyPSF (photFile, psfFile, view);
+
+    // psphotSaveImage (photFile->fpa->hdu->header, photRO->image, "findsrc.im.fits");
+    // psphotSaveImage (photFile->fpa->hdu->header, photRO->variance, "findsrc.wt.fits");
+    // psphotSaveImage (photFile->fpa->hdu->header, photRO->mask, "findsrc.mk.fits");
+
+    // erase the overlays from a previous psphot-related step
+    if (pmVisualIsVisual()) {
+        //      psphotVisualEraseOverlays (1, "all");
+    }
+
+    if (!psphotReadoutForcedKnownSources(config, view, "PSPHOT.INPUT", sources)) {
+        // This is likely a data quality issue
+        // XXX Split into multiple cases using error codes?
+        psErrorStackPrint(stderr, "Unable to perform photometry on image");
+        psWarning("Unable to perform photometry on image --- suspect bad data quality.");
+        ppSubDataQuality(data, psErrorCodeLast(), PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
+    }
+    // save the outputs on PPSUB.POS1.SOURCES
+    if (!psphotCopyResults (&foundDetections, outputFile, photFile, view)) {
+	psError(PPSUB_ERR_PROG, false, "Unable to copy psphot outputs");
+	return false;
+    }
+
+    float newTime = psTimerClear("PPSUB_PHOT"); // Time for photometry
+    float oldTime = psMetadataLookupF32(&mdok, data->stats, "TIME_PHOT"); // Previous time for photometry
+    float elapsed = isfinite(oldTime) ? oldTime + newTime : newTime;
+    psMetadataAddF32(data->stats, PS_LIST_TAIL, "TIME_PHOT", PS_META_REPLACE, "Time to do photometry", elapsed);
+
+    return true;
+}
Index: /branches/czw_branch/20101203/ppSub/src/ppSubReadoutPhotometry.c
===================================================================
--- /branches/czw_branch/20101203/ppSub/src/ppSubReadoutPhotometry.c	(revision 30117)
+++ /branches/czw_branch/20101203/ppSub/src/ppSubReadoutPhotometry.c	(revision 30118)
@@ -31,14 +31,4 @@
 
     if (!data->photometry) {
-        return true;
-    }
-
-    // Look up recipe values
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
-    psAssert(recipe, "We checked this earlier, so it should be here.");
-
-    if (!psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
-        pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL");
-        pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL.STDEV");
         return true;
     }
@@ -81,5 +71,5 @@
     }
 
-    if (!psphotReadoutMinimal(config, view)) {
+    if (!psphotReadoutMinimal(config, view, "PSPHOT.INPUT")) {
         // This is likely a data quality issue
         // XXX Split into multiple cases using error codes?
@@ -90,4 +80,5 @@
 
     // If no sources were found, there's no error,  but we want to trigger 'bad quality'
+    psWarning("no sources found: why is this being set to bad quality??");
     pmDetections *detections = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.DETECTIONS"); // Sources
     if (!detections) {
@@ -136,7 +127,4 @@
         }
     }
-
-    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL");
-    pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL.STDEV");
 
     return true;
Index: /branches/czw_branch/20101203/psLib/src/fits/psFitsImage.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/fits/psFitsImage.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/fits/psFitsImage.c	(revision 30118)
@@ -900,6 +900,11 @@
 
     if (nAxis == 2) {
+	psImage *image = psFitsReadImage(fits, region, 0);
+	if (!image) {
+            psFitsError(status, true, "Could not read image into cube");
+            return NULL;
+	}
         psArray *images = psArrayAlloc(1); // Single image plane
-        images->data[0] = psFitsReadImage(fits, region, 0);
+        images->data[0] = image;
         return images;
     }
Index: /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.c	(revision 30118)
@@ -48,8 +48,10 @@
 
 // map defines the output image dimensions and scaling.
-bool psImageMapFit(psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
+bool psImageMapFit(bool *pGoodFit, psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
                    const psVector *x, const psVector *y, const psVector *f, const psVector *df)
 {
     // XXX Add Asserts
+
+    *pGoodFit = false;
 
     // dimensions of the output map image
@@ -81,4 +83,7 @@
         map->map->data.F32[0][0]   = psStatsGetValue(map->stats, mean);
         map->error->data.F32[0][0] = psStatsGetValue(map->stats, stdev);
+        if (isfinite(map->map->data.F32[0][0]) && isfinite( map->error->data.F32[0][0])) {
+            *pGoodFit = true;
+        }
         return true;
     }
@@ -86,10 +91,10 @@
     if (Nx == 1) {
         bool status;
-        status = psImageMapFit1DinY (map, mask, maskValue, x, y, f, df);
+        status = psImageMapFit1DinY (pGoodFit, map, mask, maskValue, x, y, f, df);
         return status;
     }
     if (Ny == 1) {
         bool status;
-        status = psImageMapFit1DinX (map, mask, maskValue, x, y, f, df);
+        status = psImageMapFit1DinX (pGoodFit, map, mask, maskValue, x, y, f, df);
         return status;
     }
@@ -310,8 +315,7 @@
 
     if (!psMatrixGJSolve(A, B)) {
-        psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.  Returning NULL.\n");
         psFree (A);
         psFree (B);
-        return false;
+        return true;
     }
 
@@ -337,9 +341,10 @@
     psFree (Empty);
 
+    *pGoodFit = true;
     return true;
 }
 
 // measure residuals on each pass and clip outliers based on stats
-bool psImageMapClipFit(psImageMap *map, psStats *stats, psVector *inMask, psVectorMaskType maskValue,
+bool psImageMapClipFit(bool *pGoodFit, psImageMap *map, psStats *stats, psVector *inMask, psVectorMaskType maskValue,
                        const psVector *x, const psVector *y, const psVector *f, const psVector *df)
 {
@@ -351,4 +356,6 @@
     psAssert(f, "impossible");
 
+    *pGoodFit = false;
+
     // the user supplies one of various stats option pairs,
     // determine the desired mean and stdev STATS options:
@@ -393,5 +400,5 @@
         psTrace("psLib.imageops", 6, "Loop iteration %d.  Calling psImageMapFit()\n", N);
         psS32 Nkeep = 0;
-        if (!psImageMapFit(map, mask, maskValue, x, y, f, df)) {
+        if (!psImageMapFit(pGoodFit, map, mask, maskValue, x, y, f, df)) {
             psError(PS_ERR_UNKNOWN, false, "Could not fit image map.\n");
             psFree(resid);
@@ -399,4 +406,8 @@
             return false;
         }
+	if (!*pGoodFit) {
+	    psWarning ("bad fit to image map, try something else");
+	    return true;
+	}
 
         psVector *fit = psImageMapEvalVector(map, mask, maskValue, x, y);
@@ -454,13 +465,16 @@
     psFree(resid);
     if (!inMask) psFree (mask);
+    *pGoodFit = true; // XXX probably don't need to set this (set by psImageMapFit)
     return true;
 }
 
 // map defines the output image dimensions and scaling.
-bool psImageMapFit1DinY(psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
+bool psImageMapFit1DinY(bool *pGoodFit, psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
                         const psVector *x, const psVector *y, const psVector *f, const psVector *df)
 {
     // XXX Add Asserts
     assert (map->binning->nXruff == 1);
+
+    *pGoodFit = false;
 
     // dimensions of the output map image
@@ -578,9 +592,8 @@
 
     if (!psMatrixGJSolve(A, B)) {
-        psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations.\n");
         psFree (A);
         psFree (B);
 	psFree (Empty);
-        return false;
+        return true;
     }
 
@@ -602,13 +615,16 @@
     psFree (Empty);
 
+    *pGoodFit = true;
     return true;
 }
 
 // map defines the output image dimensions and scaling.
-bool psImageMapFit1DinX(psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
+bool psImageMapFit1DinX(bool *pGoodFit, psImageMap *map, const psVector *mask, psVectorMaskType maskValue,
                         const psVector *x, const psVector *y, const psVector *f, const psVector *df)
 {
     // XXX Add Asserts
     assert (map->binning->nYruff == 1);
+
+    *pGoodFit = false;
 
     // dimensions of the output map image
@@ -726,9 +742,8 @@
 
     if (!psMatrixGJSolve(A, B)) {
-        psError(PS_ERR_UNKNOWN, false, "Could not solve linear equations..\n");
         psFree (A);
         psFree (B);
 	psFree (Empty);
-        return false;
+        return true;
     }
 
@@ -750,4 +765,5 @@
     psFree (Empty);
 
+    *pGoodFit = true;
     return true;
 }
Index: /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.h
===================================================================
--- /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.h	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/imageops/psImageMapFit.h	(revision 30118)
@@ -8,5 +8,6 @@
 
 // fit the image map to a set of points
-bool psImageMapFit(psImageMap *map,
+bool psImageMapFit(bool *pGoodFit, 
+		   psImageMap *map,
                    const psVector *mask,
                    psVectorMaskType maskValue, // 
@@ -18,5 +19,6 @@
 
 // fit the image map to a set of points
-bool psImageMapClipFit(psImageMap *map,
+bool psImageMapClipFit(bool *pGoodFit, 
+		       psImageMap *map,
                        psStats *stats,
                        psVector *mask,  // WARNING: Mask is modified!
@@ -28,5 +30,6 @@
     );
 
-bool psImageMapFit1DinY(psImageMap *map,
+bool psImageMapFit1DinY(bool *pGoodFit, 
+			psImageMap *map,
                         const psVector *mask,
                         psVectorMaskType maskValue,
@@ -37,5 +40,6 @@
     );
 
-bool psImageMapFit1DinX(psImageMap *map,
+bool psImageMapFit1DinX(bool *pGoodFit, 
+			psImageMap *map,
                         const psVector *mask,
                         psVectorMaskType maskValue,
Index: /branches/czw_branch/20101203/psLib/src/jpeg/psImageJpeg.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/jpeg/psImageJpeg.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/jpeg/psImageJpeg.c	(revision 30118)
@@ -167,5 +167,8 @@
   int dy = image->numRows;
   
-  bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy);
+  int Npalette;
+  png_color *palette = KapaPNGPalette (&Npalette);
+
+  bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy, 1, palette, Npalette);
 
   return bdbuf;
@@ -180,6 +183,5 @@
   int dy = bdbuf->Ny;
 
-  int Npalette;
-  png_color *palette = KapaPNGPalette (&Npalette);
+  png_color *palette = bdbuf->palette;
   bDrawColor white = KapaColorByName ("white");
   for (int j = 0; j < dy; j++) {
@@ -336,15 +338,18 @@
 
     // set the scalebar labels
+    int Npalette;
+    png_color *palette = KapaPNGPalette (&Npalette);
+
     char string[64];
-    bDrawBuffer *labels = bDrawBufferCreate(dx, PS_JPEG_LABELPAD);
+    bDrawBuffer *labels = bDrawBufferCreate(dx, PS_JPEG_LABELPAD, 1, palette, Npalette);
     SetRotFont ("helvetica", 8);
-    bDrawSetBuffer(labels);
     sprint_double (string, options->min);
-    bDrawRotText(2, 2, string, 2, 0.0);
+    bDrawRotText(labels, 2, 2, string, 2, 0.0);
     sprint_double (string, options->max);
-    bDrawRotText(dx - 2, 2, string, 0, 0.0);
+    bDrawRotText(labels, dx - 2, 2, string, 0, 0.0);
     sprint_double (string, 0.5*(options->min + options->max));
-    bDrawRotText(0.5*dx, 2, string, 1, 0.0);
+    bDrawRotText(labels, 0.5*dx, 2, string, 1, 0.0);
     psImageJpegOverlayDraw(jpegImage, labels, 0, offset);
+    bDrawBufferFree(labels);
   }
     
Index: /branches/czw_branch/20101203/psLib/src/math/psStats.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/math/psStats.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/math/psStats.c	(revision 30118)
@@ -827,5 +827,5 @@
         // values; nearly bi-modal distribution).  if so, keep only points within 5? 10?
         // bins of that excess bin:
-        int nMaxBin = 0;
+        int nMaxBin = histogram->nums->data.F32[0];
         int iMaxBin = 0;
         for (long i = 1; i < histogram->nums->n; i++) {
@@ -843,6 +843,6 @@
                 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskVal) continue;
                 bool invalid = false;
-                invalid |= (myVector->data.F32[i] <= minKeep);
-                invalid |= (myVector->data.F32[i] >= maxKeep);
+                invalid |= (myVector->data.F32[i] < minKeep);
+                invalid |= (myVector->data.F32[i] > maxKeep);
                 invalid |= (!isfinite(myVector->data.F32[i]));
                 if (!invalid) continue;
@@ -852,5 +852,6 @@
 
             if (nInvalid) {
-              psTrace(TRACE, 6, "data is concentrated in a single bin, masking %d extreme outliers and retrying\n", nInvalid);
+              psTrace(TRACE, 6, "data is concentrated in a single bin (%d = %f - %f), masking %d extreme outliers and retrying\n", 
+		      iMaxBin, histogram->bounds->data.F32[iMaxBin], histogram->bounds->data.F32[iMaxBin+1], nInvalid);
               psFree(histogram);
               psFree(cumulative);
@@ -1108,6 +1109,16 @@
     // If the mean is NAN, then generate a warning and set the stdev to NAN.
     if (isnan(stats->robustMedian)) {
-        stats->fittedStdev = NAN;
-        stats->fittedStdev = NAN;
+	stats->fittedMean = NAN;
+	stats->fittedStdev = NAN;
+	stats->results |= PS_STAT_FITTED_MEAN;
+	stats->results |= PS_STAT_FITTED_STDEV;
+        return true;
+    }
+
+    if (stats->robustStdev <= FLT_EPSILON) {
+	stats->fittedMean = stats->robustMedian;
+	stats->fittedStdev = stats->robustStdev;
+	stats->results |= PS_STAT_FITTED_MEAN;
+	stats->results |= PS_STAT_FITTED_STDEV;
         return true;
     }
@@ -1289,7 +1300,16 @@
     // If the mean is NAN, then generate a warning and set the stdev to NAN.
     if (isnan(stats->robustMedian)) {
-        stats->fittedStdev = NAN;
-        stats->fittedStdev = NAN;
-        psTrace(TRACE, 4, "---- %s() end ----\n", __func__);
+	stats->fittedMean = NAN;
+	stats->fittedStdev = NAN;
+	stats->results |= PS_STAT_FITTED_MEAN_V2;
+	stats->results |= PS_STAT_FITTED_STDEV_V2;
+        return true;
+    }
+
+    if (stats->robustStdev <= FLT_EPSILON) {
+	stats->fittedMean = stats->robustMedian;
+	stats->fittedStdev = stats->robustStdev;
+	stats->results |= PS_STAT_FITTED_MEAN_V2;
+	stats->results |= PS_STAT_FITTED_STDEV_V2;
         return true;
     }
@@ -1486,7 +1506,16 @@
     // If the mean is NAN, then generate a warning and set the stdev to NAN.
     if (isnan(stats->robustMedian)) {
-        stats->fittedStdev = NAN;
-        stats->fittedStdev = NAN;
-        psTrace(TRACE, 4, "---- %s() end ----\n", __func__);
+	stats->fittedMean = NAN;
+	stats->fittedStdev = NAN;
+	stats->results |= PS_STAT_FITTED_MEAN_V3;
+	stats->results |= PS_STAT_FITTED_STDEV_V3;
+        return true;
+    }
+
+    if (stats->robustStdev <= FLT_EPSILON) {
+	stats->fittedMean = stats->robustMedian;
+	stats->fittedStdev = stats->robustStdev;
+	stats->results |= PS_STAT_FITTED_MEAN_V3;
+	stats->results |= PS_STAT_FITTED_STDEV_V3;
         return true;
     }
@@ -1782,5 +1811,19 @@
 
     // If the mean is NAN, then generate a warning and set the stdev to NAN.
-    if (isnan(stats->robustMedian)) goto escape;
+    if (isnan(stats->robustMedian)) {
+	stats->fittedMean = NAN;
+	stats->fittedStdev = NAN;
+	stats->results |= PS_STAT_FITTED_MEAN_V4;
+	stats->results |= PS_STAT_FITTED_STDEV_V4;
+        return true;
+    }
+
+    if (stats->robustStdev <= FLT_EPSILON) {
+	stats->fittedMean = stats->robustMedian;
+	stats->fittedStdev = stats->robustStdev;
+	stats->results |= PS_STAT_FITTED_MEAN_V4;
+	stats->results |= PS_STAT_FITTED_STDEV_V4;
+        return true;
+    }
 
     float guessStdev = stats->robustStdev;  // pass the guess sigma
Index: /branches/czw_branch/20101203/psLib/src/sys/psSlurp.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/sys/psSlurp.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/sys/psSlurp.c	(revision 30118)
@@ -27,5 +27,22 @@
 #include "psMemory.h"
 
-#define SLURP_SIZE 4096
+# define SLURP_SIZE 4096
+
+# if (PS_SLURP_GZIP) 
+
+psString psSlurpFD(int fd) {
+
+ gzFile file = gzdopen (fd, "r");
+ if (file == Z_NULL) {
+     psError(PS_ERR_IO, true, "Failed to open file\n");
+     return NULL;
+ }
+ 
+ psString str = psSlurpGZIP(file);
+
+ return str;
+}
+
+# else
 
 psString psSlurpFD(int fd)
@@ -38,5 +55,5 @@
         // increase the allocated string size
         size += SLURP_SIZE;
-        str = psRealloc(str, size);
+        str = psStringRealloc(str, size);
 
         // read a block from the stream
@@ -59,5 +76,38 @@
     return str;
 }
+# endif
 
+# if (PS_SLURP_GZIP)
+psString psSlurpGZIP(gzFile fd)
+{
+    psString str = NULL;                // String to which to write
+    size_t size  = 1;                   // bytes allocated -  make sure there is room for '\0'
+    size_t used = 0;                    // bytes actually used
+    ssize_t bytes;                      // Number of bytes read
+    do {
+        // increase the allocated string size
+        size += SLURP_SIZE;
+        str = psStringRealloc(str, size);
+
+        // read a block from the stream
+        bytes = gzread(fd, str + used, SLURP_SIZE);
+        if (bytes < 0) {
+            // it's an error
+            psError(PS_ERR_IO, true, "slurp failed on read");
+            psFree(str);
+            return NULL;
+        }
+
+        // Increase the size of the known string
+        used += bytes;
+
+    } while (bytes != 0);
+
+    // append '\0' to the end of the string
+    str[used] = '\0';
+
+    return str;
+}
+# endif
 
 psString psSlurpFile(FILE *stream)
@@ -70,4 +120,20 @@
 {
     PS_ASSERT_PTR_NON_NULL(filename, NULL);
+    
+# if (PS_SLURP_GZIP)
+    gzFile fd = gzopen(filename, "r");
+    if (fd == Z_NULL) {
+        psError(PS_ERR_IO, true, "Failed to open specified file, %s\n", filename);
+        return NULL;
+    }
+    psString text = psSlurpGZIP(fd);
+
+    if (gzclose(fd) != Z_OK) {
+        psError(PS_ERR_IO, true, "Failed to close specified file, %s\n", filename);
+        psFree(text);
+        return NULL;
+    }
+
+# else
 
     int fd = open(filename, O_RDONLY);
@@ -76,5 +142,4 @@
         return NULL;
     }
-
     psString text = psSlurpFD(fd);
 
@@ -84,4 +149,5 @@
         return NULL;
     }
+# endif
 
     return text;
Index: /branches/czw_branch/20101203/psLib/src/sys/psSlurp.h
===================================================================
--- /branches/czw_branch/20101203/psLib/src/sys/psSlurp.h	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/sys/psSlurp.h	(revision 30118)
@@ -12,4 +12,10 @@
 
 #include <psString.h>
+
+# define PS_SLURP_GZIP 1
+
+# if (PS_SLURP_GZIP) 
+# include <zlib.h>
+# endif
 
 /// @addtogroup FileIO Input/Output
@@ -31,4 +37,8 @@
                     );
 
+# if (PS_SLURP_GZIP)
+psString psSlurpGZIP(gzFile fd);
+# endif
+
 /// @}
 #endif
Index: /branches/czw_branch/20101203/psLib/src/sys/psString.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/sys/psString.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/sys/psString.c	(revision 30118)
@@ -48,4 +48,21 @@
     psString string = p_psAlloc(file, lineno, func, nChar + 1);
     psMemSetDeallocator(string, (psFreeFunc)stringFree);
+
+    return string;
+}
+
+
+psString p_psStringRealloc(const char *file,
+			   unsigned int lineno,
+			   const char *func,
+			   psString string,
+			   size_t nChar)
+{
+    if (!string) {
+	string = p_psAlloc(file, lineno, func, nChar + 1);
+	psMemSetDeallocator(string, (psFreeFunc)stringFree);
+    } else {
+        string = p_psRealloc(file, lineno, func, string, nChar + 1);
+    }
 
     return string;
Index: /branches/czw_branch/20101203/psLib/src/sys/psString.h
===================================================================
--- /branches/czw_branch/20101203/psLib/src/sys/psString.h	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/sys/psString.h	(revision 30118)
@@ -40,5 +40,4 @@
 #define PS_FILE_LINE p_psFileLine(__FILE__,__LINE__)
 
-
 /** Allocates a new psString.
  *
@@ -60,4 +59,24 @@
 #endif // ifdef DOXYGEN
 
+/** Reallocate an existing psString (or alloc if not existent)
+ *
+ *  @return psString:       string of length n.
+ */
+#ifdef DOXYGEN
+psString psStringRealloc(
+    psString string,
+    size_t nChar                        ///< Size of psString to allocate.
+);
+#else // ifdef DOXYGEN
+psString p_psStringRealloc(
+    const char *file,                   ///< File of caller
+    unsigned int lineno,                ///< Line number of caller
+    const char *func,                   ///< Function name of caller
+    psString string,			///< supplied string or NULL
+    size_t nChar                        ///< Size of psString to allocate.
+) PS_ATTR_MALLOC;
+#define psStringRealloc(string, nChar)				\
+    p_psStringRealloc(__FILE__, __LINE__, __func__, string, nChar)
+#endif // ifdef DOXYGEN
 
 /** Checks the type of a particular pointer.
Index: /branches/czw_branch/20101203/psLib/src/types/psMetadata.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/types/psMetadata.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/types/psMetadata.c	(revision 30118)
@@ -1371,5 +1371,5 @@
             break;
         case PS_DATA_S64:
-            fprintf(fd, "%jd\n", item->data.S64);
+            fprintf(fd, "%" PRId64 "\n", item->data.S64);
             break;
         case PS_DATA_U8:
@@ -1383,5 +1383,5 @@
             break;
         case PS_DATA_U64:
-            fprintf(fd, "%ju\n", item->data.U64);
+            fprintf(fd, "%" PRIu64 "\n", item->data.U64);
             break;
         case PS_DATA_F32:
@@ -1458,5 +1458,5 @@
               fprintf(fd, "U64  ");
               for (int i = 0; i < vector->n; i++) {
-                  fprintf(fd, "%ju ", vector->data.U64[i]);
+                  fprintf(fd, "%" PRIu64, vector->data.U64[i]);
               }
               fprintf(fd, "\n");
@@ -1486,5 +1486,5 @@
               fprintf(fd, "S64  ");
               for (int i = 0; i < vector->n; i++) {
-                  fprintf(fd, "%jd ", vector->data.S64[i]);
+                  fprintf(fd, "%" PRId64, vector->data.S64[i]);
               }
               fprintf(fd, "\n");
Index: /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.c
===================================================================
--- /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.c	(revision 30118)
@@ -1630,36 +1630,66 @@
 }
 
-
-bool psMetadataConfigWrite(psMetadata *md,
-                           const char *filename)
-{
-    PS_ASSERT_METADATA_NON_NULL(md, NULL);
-    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
-    FILE *file;
-    if ( !(file = fopen(filename, "w")) ) {
-        psError(PS_ERR_IO, true,
-                "Failed to open specified file, %s\n", filename);
-        return false;
-    }
-    psString fileString = NULL;
-    fileString = psMetadataConfigFormat(md);
-    if (fileString == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psMetadataConfigFormat returned NULL.\n");
-        return false;
-    }
-    if (fprintf(file, "%s", fileString) != strlen(fileString)) {
-        psError(PS_ERR_IO, true, "Failed to write contents of configuration file %s", filename);
-        psFree(fileString);
-        fclose(file);
-        return false;
+bool psMetadataConfigWrite(psMetadata *md, const char *filename, const char *compress)
+{
+  PS_ASSERT_METADATA_NON_NULL(md, NULL);
+  PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
+
+  psString fileString = NULL;
+  fileString = psMetadataConfigFormat(md);
+  if (fileString == NULL) {
+    psError(PS_ERR_BAD_PARAMETER_NULL, false, "psMetadataConfigFormat returned NULL.\n");
+    return false;
+  }
+
+  if (compress) {
+    if (strlen(compress) > 2) {
+      psError(PS_ERR_BAD_PARAMETER_VALUE, true, "invalid compression options %s", compress);
+      psFree(fileString);
+      return false;
+    }
+    char modeString[4];
+    snprintf (modeString, 4, "w%s", compress);
+
+    gzFile file = gzopen(filename, modeString);
+    if (file == Z_NULL) {
+      psError(PS_ERR_IO, true, "Failed to open specified file, %s\n", filename);
+      psFree(fileString);
+      return false;
+    }
+
+    int nbytes = gzwrite (file, fileString, strlen(fileString));
+    if (nbytes != strlen(fileString)) {
+      psError(PS_ERR_IO, true, "Failed to write contents of configuration file %s", filename);
+      psFree(fileString);
+      gzclose(file);
+      return false;
+    }
+    psFree(fileString);
+    if (gzclose(file) != Z_OK) {
+      psError(PS_ERR_IO, true, "Failed to close file, %s\n", filename);
+      return false;
+    }
+  } else {
+    FILE *file = fopen(filename, "w");
+    if (file == NULL) {
+      psError(PS_ERR_IO, true, "Failed to open specified file, %s\n", filename);
+      psFree(fileString);
+      return false;
+    }
+
+    int nbytes = fwrite(fileString, 1, strlen(fileString), file);
+    if (nbytes != strlen(fileString)) {
+      psError(PS_ERR_IO, true, "Failed to write contents of configuration file %s", filename);
+      psFree(fileString);
+      fclose(file);
+      return false;
     }
     psFree(fileString);
     if (fclose(file) == EOF) {
-        psError(PS_ERR_IO, true,
-                "Failed to close file, %s\n", filename);
-        return false;
-    }
-    return true;
+      psError(PS_ERR_IO, true, "Failed to close file, %s\n", filename);
+      return false;
+    }
+  }
+  return true;
 }
 
Index: /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.h
===================================================================
--- /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.h	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/src/types/psMetadataConfig.h	(revision 30118)
@@ -33,4 +33,5 @@
  *  a string, the formatting command must also be for a string. If the
  *  metadata type is any other data type, printing is not allowed.
+ *  Currently, this function does not compress the output file
  *
  * @return psMetadataItem* :    Pointer metadata item.
@@ -85,9 +86,11 @@
 bool psMetadataConfigWrite(
     psMetadata *md,                    ///< The metadata to convert
-    const char *filename               ///< Name of file to write
+    const char *filename,	       ///< Name of file to write
+    const char *compress	       ///< Output compression options 
 );
 
 /** Converts a psMetadata structure (including any nested psMetadata) into a
  *  configuration file formatted string that is written a file stream.
+ *  Currently, this function does not compress the output file
  *
  *  @return bool:       True if successful, otherwise false.
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psCoord.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psCoord.c	(revision 30117)
+++ 	(revision )
@@ -1,469 +1,0 @@
-/** @file  tst_psCoord.c
-*
-*  @brief The code will ...
-*
-*
-*  @author GLG, MHPCC
-*
-*  @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-02-28 02:53:03 $
-*
-*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
-*/
-
-#include "psTest.h"
-#include "pslib_strict.h"
-static psS32 testPlaneTransformAlloc(void);
-static psS32 testPlaneDistortAlloc(void);
-static psS32 testPlaneAlloc(void);
-static psS32 testPlaneTransformApply(void);
-static psS32 testPlaneDistortApply(void);
-static psS32 testPixelsTransform(void);
-
-testDescription tests[] = {
-                              {testPlaneTransformAlloc, 826, "psPlaneTransformAlloc()", 0, false},
-                              {testPlaneDistortAlloc, 827, "psPlaneDistortAlloc()", 0, false},
-                              {testPlaneAlloc, -1, "psPlaneAlloc()", 0, false},
-                              {testPlaneTransformApply, 831, "psPlaneTransformApply()", 0, false},
-                              {testPlaneDistortApply, 832, "psPlaneDistortApply()", 0, false},
-                              {testPixelsTransform, 833, "psPixelsTransform()", 0, false},
-                              {NULL}
-                          };
-
-psS32 main( psS32 argc, char* argv[] )
-{
-    psLogSetFormat("HLNM");
-    psLogSetLevel( PS_LOG_INFO );
-
-    return ( ! runTestSuite( stderr, "psCoord", tests, argc, argv ) );
-}
-
-#define ORDER_X 2
-#define ORDER_Y 3
-#define ORDER_Z 4
-#define ORDER_T 5
-
-psS32 testPlaneAlloc( void )
-{
-    // Allocate psPlane.
-    psPlane *myP = psPlaneAlloc();
-
-    // Verify returned value is not NULL
-    if(myP == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "psPlaneAlloc() returned NULL not expected.");
-        return 1;
-    }
-
-    // Verify returned transform has members set properly
-    if (!isnan(myP->x)) {
-        psError(PS_ERR_UNKNOWN,true,"myP->x is %d, should be %d", myP->x, NAN);
-        return 2;
-    }
-
-    if (!isnan(myP->y)) {
-        psError(PS_ERR_UNKNOWN,true,"myP->y is %d, should be %d", myP->y, NAN);
-        return 3;
-    }
-
-    if (!isnan(myP->xErr)) {
-        psError(PS_ERR_UNKNOWN,true,"myP->xErr is %d, should be %d", myP->xErr, NAN);
-        return 4;
-    }
-
-    if (!isnan(myP->yErr)) {
-        psError(PS_ERR_UNKNOWN,true,"myP->yErr is %d, should be %d", myP->yErr, NAN);
-        return 5;
-    }
-
-    // Free psPlane
-    psFree(myP);
-
-    return 0;
-}
-
-psS32 testPlaneTransformAlloc( void )
-{
-    // Allocate psPlaneTransform with known x and y terms
-    psPlaneTransform *myPT = psPlaneTransformAlloc(ORDER_X, ORDER_Y);
-
-    // Verify returned value is not NULL
-    if(myPT == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Function returned NULL not expected.");
-        return 1;
-    }
-
-    // Verify returned transform has members set properly
-    if (myPT->x->nX != ORDER_X) {
-        psError(PS_ERR_UNKNOWN,true,"myPT->x->nX is %d, should be %d",
-                myPT->x->nX, ORDER_X);
-        return 2;
-    }
-    if (myPT->y->nX != ORDER_X) {
-        psError(PS_ERR_UNKNOWN,true,"myPT->y->nX is %d, should be %d",
-                myPT->y->nX, ORDER_X);
-        return 3;
-    }
-    if (myPT->x->nY != ORDER_Y) {
-        psError(PS_ERR_UNKNOWN,true,"myPT->x->nY is %d, should be %d",
-                myPT->x->nY, ORDER_Y);
-        return 4;
-    }
-    if (myPT->y->nY != ORDER_Y) {
-        psError(PS_ERR_UNKNOWN,true,"myPT->y->nY is %d, should be %d",
-                myPT->y->nY, ORDER_Y);
-        return 5;
-    }
-
-    // Free plane transform
-    psFree(myPT);
-
-    // Attempt to specify negative x order and verify NULL returned and errror message generated
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: negative x order");
-    myPT = psPlaneTransformAlloc(-1, 1);
-    if (myPT != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneTransformAlloc() did not return NULL.");
-        return 6;
-    }
-
-    // Attempt to specify negative y order and verify NULL returned and error message generated
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: negative y order");
-    myPT = psPlaneTransformAlloc(1, -1);
-    if (myPT != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneTransformAlloc() did not return NULL.");
-        return 7;
-    }
-
-    psFree(myPT);
-
-    return 0;
-}
-
-
-psS32 testPlaneDistortAlloc( void )
-{
-    // Invoke function with known parameters
-    psPlaneDistort *myPD = psPlaneDistortAlloc(ORDER_X, ORDER_Y, ORDER_Z, ORDER_T);
-
-    // Verify NULL is not returned
-    if(myPD == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Return of NULL not expected");
-        return 1;
-    }
-    // Verify the terms are properly set after allocation
-    if (myPD->x->nX != ORDER_X) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->x->nX is %d, should be %d",
-                myPD->x->nX, ORDER_X);
-        return 2;
-    }
-    if (myPD->y->nX != ORDER_X) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->y->nX is %d, should be %d",
-                myPD->y->nX, ORDER_X);
-        return 3;
-    }
-    if (myPD->x->nY != ORDER_Y) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->x->nY is %d, should be %d",
-                myPD->x->nY, ORDER_Y);
-        return 4;
-    }
-    if (myPD->y->nY != ORDER_Y) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->y->nY is %d, should be %d",
-                myPD->y->nY, ORDER_Y);
-        return 5;
-    }
-    if (myPD->x->nZ != ORDER_Z) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->x->nZ is %d, should be %d",
-                myPD->x->nZ, ORDER_Z);
-        return 6;
-    }
-    if (myPD->y->nZ != ORDER_Z) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->y->nZ is %d, should be %d",
-                myPD->y->nZ, ORDER_Z);
-        return 7;
-    }
-    if (myPD->x->nT != ORDER_T) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->x->nT is %d, should be %d",
-                myPD->x->nT, ORDER_T);
-        return 8;
-    }
-    if (myPD->y->nT != ORDER_T) {
-        psError(PS_ERR_UNKNOWN,true,"myPD->y->nT is %d, should be %d",
-                myPD->y->nT, ORDER_T);
-        return 9;
-    }
-    // Free psPlaneTransform
-    psFree(myPD);
-
-    // Invoke function with negative x order parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for negative x order");
-    myPD = psPlaneDistortAlloc(-1, 1, 1, 1);
-    if (myPD != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneDistortAlloc() did not return NULL.");
-        return 10;
-    }
-
-    // Invoke function with negative y order parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for negative y order");
-    myPD = psPlaneDistortAlloc(1, -1, 1, 1);
-    if (myPD != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneDistortAlloc() did not return NULL.");
-        return 11;
-    }
-
-    // Invoke function with negative z order parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for negative z order");
-    myPD = psPlaneDistortAlloc(1, 1, -1, 1);
-    if (myPD != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneDistortAlloc() did not return NULL.");
-        return 12;
-    }
-
-    // Invoke function with negative t order parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for negative w order");
-    myPD = psPlaneDistortAlloc(1, 1, 1, -1);
-    if (myPD != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psPlaneDistortAlloc() did not return NULL.");
-    }
-
-    return 0;
-}
-
-#define N 10
-// We do a simple identity transformation on a few x,y pairs.
-psS32 testPlaneTransformApply( void )
-{
-    psPlane*          out = NULL;
-    psPolynomial2D*  tmp2DPoly = NULL;
-    psPlane*          rc;
-
-    // Create input coordinate
-    psPlane* in = psPlaneAlloc();
-    if(in == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return from psPlaneAlloc");
-        return 1;
-    }
-
-    // Create transform
-    psPlaneTransform* pt = psPlaneTransformAlloc(2,2);
-
-    // Set transform coefficients so the x coord input will equal x coord output, same for y
-    pt->x->coeff[1][0] = 1.0;
-    pt->y->coeff[0][1] = 1.0;
-
-    // Apply transform for several points
-    for (psS32 i = 0; i < N; i++) {
-        in->x = (psF64) i;
-        in->y = (psF64) (i + 5.0);
-        in->xErr = 0.0;
-        in->yErr = 0.0;
-
-        // Verify function does not return NULL
-        out = psPlaneTransformApply(out, pt, in);
-        if( out  == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Expected non-NULL return value");
-            return 1;
-        }
-        // Verify the expected values are returned
-        if (FLT_EPSILON < fabs(out->x - in->x)) {
-            psError(PS_ERR_UNKNOWN,true,"out.x is %lf, should be %lf", out->x, in->x);
-            return 3;
-        }
-        if (FLT_EPSILON < fabs(out->y - in->y)) {
-            psError(PS_ERR_UNKNOWN,true,"out.y is %lf, should be %lf", out->y, in->y);
-            return 4;
-        }
-    }
-    psFree(out);
-
-    // Verify return null and error message generater for null specified transform
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL psPlaneTransform");
-    rc = psPlaneTransformApply(NULL, NULL, in);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Function did not return NULL as expected for NULL psPlaneTransform.");
-        return 5;
-    }
-
-    // Verify return null and error message generated for null psPlaneTransform x coeff
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL x coeff psPlaneTransform");
-    tmp2DPoly = pt->x;
-    pt->x = NULL;
-    rc = psPlaneTransformApply(NULL, pt, in);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Function did not return NULL as expected for NULL x coeff psPlaneTransform");
-        return 6;
-    }
-    pt->x = tmp2DPoly;
-
-    // Verify return null and error message generated for null psPlaneTransform y coeff
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL y coeff psPlaneTransform");
-    tmp2DPoly = pt->y;
-    pt->y = NULL;
-    rc = psPlaneTransformApply(NULL, pt, in);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Function did not return NULL as expected for NULL y coeff psPlaneTransform");
-        return 7;
-    }
-    pt->y = tmp2DPoly;
-
-    // Verify return null and error message generated for null psPlane coordinate
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL psPlane");
-    rc = psPlaneTransformApply(NULL, pt, NULL);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Function did not return NULL as expected for NULL psPlane");
-        return 8;
-    }
-
-    psFree(pt);
-    psFree(in);
-
-    return 0;
-}
-
-#define COLOR 1.0
-#define MAGNITUDE 1.0
-// We do a simple identity transformation on a few x,y pairs.  For x and y,
-// we add in the COLOR and MAGNITUDE.
-psS32 testPlaneDistortApply( void )
-{
-    psPlane*         out       = NULL;
-    psPlane*         rc        = NULL;
-    psPolynomial4D* tmp4DPoly = NULL;
-
-    // Allocate input coordinate
-    psPlane* in = psPlaneAlloc();
-
-    // Create psPlaneTransform structure
-    psPlaneDistort*  pt = psPlaneDistortAlloc(2, 2, 2, 2);
-
-    pt->x->coeff[1][0][0][0] = 1.0;
-    pt->x->coeff[0][0][1][0] = 1.0;
-    pt->x->coeff[0][0][0][1] = 1.0;
-
-    pt->y->coeff[0][1][0][0] = 1.0;
-    pt->y->coeff[0][0][1][0] = 1.0;
-    pt->y->coeff[0][0][0][1] = 1.0;
-
-    for (psS32 i = 0; i < N; i++) {
-        in->x = (psF64) i;
-        in->y = (psF64) (i + 5.0);
-        in->xErr = 0.0;
-        in->yErr = 0.0;
-        out = psPlaneDistortApply(out, pt, in, COLOR, MAGNITUDE);
-
-        // Verify return value is not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Expected non-NULL return");
-            return 1;
-        }
-        // Verify return value contains expected values
-        if (FLT_EPSILON < fabs(out->x - COLOR - MAGNITUDE - in->x)) {
-            psError(PS_ERR_UNKNOWN,true,"out->x is %lf, should be %lf",
-                    out->x, in->x + COLOR + MAGNITUDE);
-            return 2;
-        }
-        if (FLT_EPSILON < fabs(out->y - COLOR - MAGNITUDE - in->y)) {
-            psError(PS_ERR_UNKNOWN,true,"out->y is %lf, should be %lf",
-                    out->y, in->y + COLOR + MAGNITUDE);
-            return 3;
-        }
-    }
-    psFree(out);
-
-    // Attempt to invoke psPlaneDistortApply with NULL psPlaneDistort
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null psPlaneDistort");
-    rc = psPlaneDistortApply(NULL, NULL, in, COLOR, MAGNITUDE);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL.");
-        return 4;
-    }
-
-    // Attempt to invoke psPlaneDistortApply with NULL psPlaneDistort x member
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null x member psPlaneDistort");
-    tmp4DPoly = pt->x;
-    pt->x = NULL;
-    rc = psPlaneDistortApply(NULL, pt, in, COLOR, MAGNITUDE);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL.");
-        return 5;
-    }
-    pt->x = tmp4DPoly;
-
-    // Attempt to invoke psPlaneDistortApply with NULL psPlaneDistort y member
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null y member psPlaneDistort");
-    tmp4DPoly = pt->y;
-    pt->y = NULL;
-    rc = psPlaneDistortApply(NULL, pt, in, COLOR, MAGNITUDE);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL.");
-        return 6;
-    }
-    pt->y = tmp4DPoly;
-
-    // Attempt to invoke psPlaneDistortApply with NULL input psPlane
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null input psPlane");
-    rc = psPlaneDistortApply(NULL, pt, NULL, COLOR, MAGNITUDE);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL");
-        return 7;
-    }
-
-    psFree(pt);
-    psFree(in);
-
-    return 0;
-}
-
-psS32 testPixelsTransform(void)
-{
-    psPixels *input = NULL;
-    psPixels *output = NULL;
-    psPlaneTransform *trans = psPlaneTransformAlloc(1, 3);
-
-    //Return NULL for NULL input pixels
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    output = psPixelsTransform(output, input, trans);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psPixelsTransform failed to return NULL for NULL input pixels.\n");
-        return 1;
-    }
-    //Return NULL for NULL input PlaneTransform
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    output = psPixelsTransform(output, input, NULL);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psPixelsTransform failed to return NULL for NULL psPlaneTransform.\n");
-        return 2;
-    }
-
-    input = psPixelsAlloc(2);
-    input->n = 2;
-    input->data[0].x = 1.0;
-    input->data[0].y = 1.0;
-    input->data[1].x = 1.0;
-    input->data[1].y = 6.0;
-    trans->x->coeff[0][0] = 0;
-    trans->x->coeff[1][0] = 1.0;
-    trans->y->coeff[0][0] = 0;
-    trans->y->coeff[0][0] = 0;
-    trans->y->coeff[0][2] = 0.5;
-
-    //Verify that the output pixels are what we expected
-    output = psPixelsTransform(output, input, trans);
-    int nExpected = 9;
-    if (output->n != nExpected) {
-        psError(PS_ERR_BAD_PARAMETER_SIZE, false,
-                "psPixelsTransform failed to return the expected number of pixels.\n");
-        printf("\n output returned with %ld pixels\n\n", output->n);
-        for (int i = 0; i < output->n; i++) {
-            printf("  (%6.2lf, %6.2lf) pixel %d\n", output->data[i].x, output->data[i].y, i+1);
-        }
-        return 3;
-    }
-
-    psFree(trans);
-    psFree(input);
-    psFree(output);
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psCoord01.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psCoord01.c	(revision 30117)
+++ 	(revision )
@@ -1,999 +1,0 @@
-/**  @file  tst_psCoord01.c
-*
-*    @brief  The code will test several functions with PSLib source file
-*            psCoord.c
-*
-*    @author Eric Van Alst, MHPCC
-*
-* XXX: must do (r,d) -> (x, y) -> (r, d) test to ensure correctness.
-* XXX: The (Xs, Ys) scales are not be used properly.
-*
-*
-*    @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
-*    @date  $Date: 2006-05-26 01:23:41 $
-*    @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
-*    @date  $Date: 2006-05-26 01:23:41 $
-*
-*    Copyright 2005 Maui High Performance Computing Center, Univ. of Hawaii
-*/
-
-#include "pslib_strict.h"
-#include "psTest.h"
-
-static psS32 testProjectionAlloc(void);
-static psS32 testProjectTan(void);
-static psS32 testDeprojectTan(void);
-static psS32 testProjectSin(void);
-static psS32 testDeprojectSin(void);
-static psS32 testProjectAit(void);
-static psS32 testDeprojectAit(void);
-static psS32 testProjectPar(void);
-static psS32 testDeprojectPar(void);
-static psS32 testProjectFail(void);
-static psS32 testDeprojectFail(void);
-static psS32 testSetOffsetSphere(void);
-static psS32 testSetOffsetLinear(void);
-static psS32 testGetOffsetSphere(void);
-static psS32 testGetOffsetLinear(void);
-static psS32 testProjectTanDeProjectTan(void);
-
-testDescription tests[] = {
-                              {testProjectionAlloc, 833, "psProjectionAlloc",0,false},
-                              {testProjectFail, 834, "psProject",0,false},
-                              {testDeprojectFail, 835, "psProject",0,false},
-                              {testSetOffsetSphere, 0000, "psSphereSetOffset",0,false},
-                              {testSetOffsetLinear, 0000, "psSphereSetOffset",0,false},
-                              {testGetOffsetSphere, 0000, "psSphereGetOffset",0,false},
-                              {testGetOffsetLinear, 0000, "psSphereGetOffset",0,false},
-                              {NULL},
-                              /* XXX: Tests removed pending valuation -- test itself may be faulty. */
-                              {testProjectTan, 834, "psProject(TAN)",0,false},
-                              {testDeprojectTan, 835, "psDeproject(TAN)",0,false},
-                              {testProjectSin, 834, "psProject(SIN)",0,false},
-                              {testDeprojectSin, 835, "psDeproject(SIN)",0,false},
-                              {testProjectAit, 834, "psProject(AIT)",0,false},
-                              {testDeprojectAit, 835, "psDeproject(AIT)",0,false},
-                              {testProjectPar, 834, "psProject(PAR)",0,false},
-                              {testDeprojectPar, 835, "psDeproject(PAR)",0,false},
-                              {testProjectTanDeProjectTan, 0000, "psProject(TAN) -> psDeproject(TAN)",0,false}
-                          };
-
-
-#define ERROR_TOL    0.0001
-#define TESTPOINTS   4
-#define DEG_INC   30.0
-
-#define MY_TINY 0.0001
-#define PS_COMPARE_TINY_THEN_PRINT_ERROR(ACTUAL, EXPECT, TESTSTATUS) \
-if (MY_TINY < fabs(EXPECT - ACTUAL)) { \
-    psError(PS_ERR_UNKNOWN,true,"%s is %lg, should be %lg", #ACTUAL, ACTUAL, EXPECT, TESTSTATUS); \
-    return TESTSTATUS; \
-}
-
-
-//  alpha, delta, alpha-center, delta-center, scale-x, scale-y
-psF64 projectionTestPoint[TESTPOINTS][6] = {
-            {  0.785398,  0.785398,  0.000000,  0.000000,  1.000000,  1.000000 },
-            {  0.100000,  1.500000,  0.500000,  0.250000,  1.000000,  1.000000 },
-            {  0.628319,  0.448799,  0.000000,  0.000000,  0.250000,  0.750000 },
-            { -1.047196,  0.222222, -0.250000,  0.000000,  1.500000,  1.250000 }
-        };
-
-// Expected values for TAN
-psF64 projectionTanExpected[TESTPOINTS][2] = {
-            { -1.000000, -1.414214 },
-            {  0.088884, -3.066567 },
-            { -0.181636, -0.446444 },
-            {  1.535818, -0.404231 }
-        };
-
-// Expected values for SIN
-psF64 projectionSinExpected[TESTPOINTS][2] = {
-            { -0.500000, -0.707101 },
-            {  0.027546, -0.950366 },
-            { -0.132394, -0.325413 },
-            {  1.046712, -0.275497 }
-        };
-
-// Expected values for AIT
-psF64 projectionAitExpected[TESTPOINTS][2] = {
-            { -0.549175,  0.523375 },
-            {  0.027895,  0.313807 },
-            { -0.162822,  0.607646 },
-            {  1.455312,  0.955388 }
-        };
-
-// Expected values for PAR
-psF64 projectionParExpected[TESTPOINTS][2] = {
-            { -0.541244,  0.545532 },
-            {  0.027703,  0.329366 },
-            { -0.157157,  0.633550 },
-            {  1.432951,  0.971372 }
-        };
-
-// Testpoints, offset and expected values for psSphereSetOffset test
-#define TESTPOINTS_OFFSET  4
-psF64 setOffsetTestpoint[TESTPOINTS_OFFSET][2] = {
-            { 0.50,  0.50 },
-            {-0.50,  0.50 },
-            { 0.00,  0.00 },
-            { 1.50, -0.10 }
-        };
-
-psF64 setOffsetOffset[TESTPOINTS_OFFSET][2] = {
-            { 0.190761, -0.272205 },
-            {-0.553049, -0.460926 },
-            { 0.100335,-14.172222 },
-            {14.172222, -0.100335 }
-        };
-
-psF64 setOffsetResult[TESTPOINTS_OFFSET][2] = {
-            //XXX: Eugene says his values are correct, so i'm changing these values to the output.
-            //            { 0.25,  0.75 },
-            //            { 0.20,  0.80 },
-            //            {-0.10,  1.50 },
-            //            { 0.00,  0.00 }
-            { 0.68702,   0.230294},
-            { -0.966388,  0.0608434 },
-            {0.10,  -1.50 },
-            { 3.00141, -0.0140538  }
-        };
-
-psF64 getOffsetTestpoint1[TESTPOINTS_OFFSET][2] = {
-            { 0.00,  0.00 },
-            {-0.25,  0.50 },
-            { 0.50, -0.25 },
-            { 0.25, -0.10 }
-        };
-
-psF64 getOffsetTestpoint2[TESTPOINTS_OFFSET][2] = {
-            { 0.75,  0.25 },
-            { 0.40, -0.60 },
-            { 1.50,  0.50 },
-            { 0.10,  0.75 }
-        };
-
-psF64 getOffsetResult[TESTPOINTS_OFFSET][2] = {
-            //XXX: Eugene says his values are correct, so i'm changing these values to the output.
-            //            { -0.931596, -0.348976 },
-            //            { -1.632830,  2.649629 },
-            //            { -2.166795, -1.707211 },
-            //            {  0.167752, -1.151351 }
-            { 0.931596, 0.348976 },
-            { 1.632830,  -2.649629 },
-            { 2.166795, 1.707211 },
-            {  -0.167752, 1.151351 }
-        };
-
-
-psS32 main( psS32 argc, char* argv[] )
-{
-    psLogSetFormat("HLNM");
-    psLogSetLevel( PS_LOG_INFO );
-
-    return ( !runTestSuite(stderr,"psCoord",tests,argc,argv) );
-}
-
-psS32 testProjectionAlloc(void)
-{
-    // Allocate new psProjection structure
-    psProjection*  myProjection = psProjectionAlloc(1.1, 2.2, 3.3, 4.4, PS_PROJ_AIT);
-
-    // Verify NULL is not returned
-    if(myProjection == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Unexpected return of NULL");
-        return 1;
-    }
-    // Verify the members are set correctly
-    if(myProjection->R != 1.1) {
-        psError(PS_ERR_UNKNOWN,true,"R member set to %lg, but expected %lg",
-                myProjection->R, 1.1);
-        return 2;
-    }
-    if(myProjection->D != 2.2) {
-        psError(PS_ERR_UNKNOWN,true,"D member set to %lg, but expected %lg",
-                myProjection->D, 2.2);
-        return 3;
-    }
-    if(myProjection->Xs != 3.3) {
-        psError(PS_ERR_UNKNOWN,true,"Xs member set to %lg, but expected %lg",
-                myProjection->Xs, 3.3);
-        return 4;
-    }
-    if(myProjection->Ys != 4.4) {
-        psError(PS_ERR_UNKNOWN,true,"Ys member set to %lg, but expected %lg",
-                myProjection->Ys, 4.4);
-        return 5;
-    }
-    if(myProjection->type != PS_PROJ_AIT) {
-        psError(PS_ERR_UNKNOWN,true,"type member set to %d, but expected %d",
-                myProjection->type, PS_PROJ_AIT);
-        return 6;
-    }
-
-    // Free projection
-    psFree(myProjection);
-
-    return 0;
-}
-
-//HEY
-psS32 testProjectTan(void)
-{
-    psPlane*       out = NULL;
-    psSphere*      in = psSphereAlloc();
-    psSphere*      inTest = NULL;
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_TAN);
-
-    // Perform projecton on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and project members
-        in->r = projectionTestPoint[i][0];
-        in->d = projectionTestPoint[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform projection
-        out = psProject(in, myProjection);
-        inTest = psDeproject(out, myProjection);
-
-        // Verify output not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return i*10+3;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->x - projectionTanExpected[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psPlane->x = %lg  expected %lg",
-                    i,out->x, projectionTanExpected[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->y - projectionTanExpected[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint % d  psPlane->y = %lg  expected %lg",
-                    i,out->y, projectionTanExpected[i][1]);
-            return i*10+2;
-        }
-
-        // Verify output is as expected
-        if(fabs(in->r - inTest->r) > ERROR_TOL) {
-            printf("TEST ER (in->r, inTest->r) (%.2f %.2f)\n", in->r, inTest->r);
-            return i*10+4;
-        }
-        if(fabs(in->d - inTest->d) > ERROR_TOL) {
-            printf("TEST ERROR: (in->d, inTest->d) (%.2f %.2f)\n", in->d, inTest->d);
-            return i*10+5;
-        }
-
-        psFree(inTest);
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testDeprojectTan(void)
-{
-    psSphere*       out = NULL;
-    psPlane*        in = psPlaneAlloc();
-    psProjection*   myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_TAN);
-
-    // Perform deprojection on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and projection members
-        in->x = projectionTanExpected[i][0];
-        in->y = projectionTanExpected[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform deprojection
-        out = psDeproject(in, myProjection);
-
-        // Verify output is not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return 20*i;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->r - projectionTestPoint[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->r = %lg  expected %lg",
-                    i,out->r,projectionTestPoint[i][0]);
-            return 20*i + 1;
-        }
-        if(fabs(out->d - projectionTestPoint[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->d = %lg expected %lg",
-                    i, out->d, projectionTestPoint[i][1]);
-            return 20*i + 2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testProjectSin(void)
-{
-    psPlane*       out = NULL;
-    psSphere*      in = psSphereAlloc();
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_SIN);
-
-    // Perform projecton on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and project members
-        in->r = projectionTestPoint[i][0];
-        in->d = projectionTestPoint[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform projection
-        out = psProject(in, myProjection);
-
-        // Verify output not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return i*10;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->x - projectionSinExpected[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psPlane->x = %lg  expected %lg",
-                    i,out->x, projectionSinExpected[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->y - projectionSinExpected[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint % d  psPlane->y = %lg  expected %lg",
-                    i,out->y, projectionSinExpected[i][1]);
-            return i*10+2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testDeprojectSin(void)
-{
-    psSphere*       out = NULL;
-    psPlane*        in = psPlaneAlloc();
-    psProjection*   myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_SIN);
-
-    // Perform deprojection on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and projection members
-        in->x = projectionSinExpected[i][0];
-        in->y = projectionSinExpected[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform deprojection
-        out = psDeproject(in, myProjection);
-
-        // Verify output is not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return 20*i;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->r - projectionTestPoint[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->r = %lg  expected %lg",
-                    i,out->r,projectionTestPoint[i][0]);
-            return 20*i + 1;
-        }
-        if(fabs(out->d - projectionTestPoint[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->d = %lg expected %lg",
-                    i, out->d, projectionTestPoint[i][1]);
-            return 20*i + 2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testProjectAit(void)
-{
-    psPlane*       out = NULL;
-    psSphere*      in = psSphereAlloc();
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_AIT);
-
-    // Perform projecton on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and project members
-        in->r = projectionTestPoint[i][0];
-        in->d = projectionTestPoint[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform projection
-        out = psProject(in, myProjection);
-
-        // Verify output not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return i*10;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->x - projectionAitExpected[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psPlane->x = %lg  expected %lg",
-                    i,out->x, projectionAitExpected[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->y - projectionAitExpected[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint % d  psPlane->y = %lg  expected %lg",
-                    i,out->y, projectionAitExpected[i][1]);
-            return i*10+2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testDeprojectAit(void)
-{
-    psSphere*       out = NULL;
-    psPlane*        in = psPlaneAlloc();
-    psProjection*   myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_AIT);
-
-    // Perform deprojection on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and projection members
-        in->x = projectionAitExpected[i][0];
-        in->y = projectionAitExpected[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform deprojection
-        out = psDeproject(in, myProjection);
-
-        // Verify output is not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return 20*i;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->r - projectionTestPoint[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->r = %lg  expected %lg",
-                    i,out->r,projectionTestPoint[i][0]);
-            return 20*i + 1;
-        }
-        if(fabs(out->d - projectionTestPoint[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->d = %lg expected %lg",
-                    i, out->d, projectionTestPoint[i][1]);
-            return 20*i + 2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testProjectPar(void)
-{
-    psPlane*       out = NULL;
-    psSphere*      in = psSphereAlloc();
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_PAR);
-
-    // Perform projecton on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and project members
-        in->r = projectionTestPoint[i][0];
-        in->d = projectionTestPoint[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform projection
-        out = psProject(in, myProjection);
-
-        // Verify output not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return i*10;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->x - projectionParExpected[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psPlane->x = %lg  expected %lg",
-                    i,out->x, projectionParExpected[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->y - projectionParExpected[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint % d  psPlane->y = %lg  expected %lg",
-                    i,out->y, projectionParExpected[i][1]);
-            return i*10+2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testDeprojectPar(void)
-{
-    psSphere*       out = NULL;
-    psPlane*        in = psPlaneAlloc();
-    psProjection*   myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_PAR);
-
-    // Perform deprojection on various test points
-    for(psS32 i = 0; i < TESTPOINTS; i++) {
-
-        // Initialize input and projection members
-        in->x = projectionParExpected[i][0];
-        in->y = projectionParExpected[i][1];
-        myProjection->R = projectionTestPoint[i][2];
-        myProjection->D = projectionTestPoint[i][3];
-        myProjection->Xs = projectionTestPoint[i][4];
-        myProjection->Ys = projectionTestPoint[i][5];
-
-        // Perform deprojection
-        out = psDeproject(in, myProjection);
-
-        // Verify output is not NULL
-        if(out == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Return null not expected");
-            return 20*i;
-        }
-
-        // Verify output is as expected
-        if(fabs(out->r - projectionTestPoint[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->r = %lg  expected %lg",
-                    i,out->r,projectionTestPoint[i][0]);
-            return 20*i + 1;
-        }
-        if(fabs(out->d - projectionTestPoint[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d  psSphere->d = %lg expected %lg",
-                    i, out->d, projectionTestPoint[i][1]);
-            return 20*i + 2;
-        }
-        psFree(out);
-    }
-
-    psFree(in);
-    psFree(myProjection);
-
-    return 0;
-}
-
-psS32 testProjectFail(void)
-{
-    psPlane*       out          = NULL;
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_TAN);
-    psSphere*      in           = psSphereAlloc();
-
-    // Invoke function with null coordinate argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null coord arg");
-    out = psProject(NULL, myProjection);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 1;
-    }
-
-    // Invoke function with null projection argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null projection arg");
-    out = psProject(in, NULL);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 2;
-    }
-
-    // Invoke function with invalid projection type
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid projection type");
-    myProjection->type = PS_PROJ_NTYPE;
-    out = psProject(in,myProjection);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 3;
-    }
-
-    psFree(myProjection);
-    psFree(in);
-
-    return 0;
-}
-
-psS32 testDeprojectFail(void)
-{
-    psSphere*      out          = NULL;
-    psProjection*  myProjection = psProjectionAlloc(0.0,0.0,1.0,1.0,PS_PROJ_TAN);
-    psPlane*       in           = psPlaneAlloc();
-
-    // Invoke function with null coordinate argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null coord arg");
-    out = psDeproject(NULL, myProjection);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 1;
-    }
-
-    // Invoke function with null projection argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null projection arg");
-    out = psDeproject(in, NULL);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 2;
-    }
-
-    // Invoke function with invalid projection type
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid projection type");
-    myProjection->type = PS_PROJ_NTYPE;
-    out = psDeproject(in,myProjection);
-    if(out != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return null as expected");
-        return 3;
-    }
-
-    psFree(myProjection);
-    psFree(in);
-
-    return 0;
-}
-
-psS32 testSetOffsetSphere( void )
-{
-    psSphere* position1 = psSphereAlloc();
-    psSphere* position2 = NULL;
-    psSphere* offset    = psSphereAlloc();
-    psSphere* tmpOffset = psSphereAlloc();
-
-    // Initialize first position
-    position1->r = DEG_TO_RAD(90.0);
-    position1->d = DEG_TO_RAD(45.0);
-    position1->rErr = 0.0;
-    position1->dErr = 0.0;
-
-    //  Using various offset verify spherical offset
-    //  Use all the valid unit types
-    for (psF64 r = 0.0; r < 180.0; r += DEG_INC) {
-        for (psF64 d = 0.0; d < 90.0; d += DEG_INC) {
-
-            offset->r = DEG_TO_RAD(r);
-            offset->d = DEG_TO_RAD(d);
-            offset->rErr = 0.0;
-            offset->dErr = 0.0;
-
-            position2 = psSphereSetOffset(position1, offset, PS_SPHERICAL, PS_RADIAN);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->r, (position1->r + offset->r), 1);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->d, (position1->d + offset->d), 2);
-            psFree(position2);
-
-            tmpOffset->r = RAD_TO_DEG(offset->r);
-            tmpOffset->d = RAD_TO_DEG(offset->d);
-            tmpOffset->rErr = 0.0;
-            tmpOffset->dErr = 0.0;
-            position2 = psSphereSetOffset(position1, tmpOffset, PS_SPHERICAL, PS_DEGREE);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->r, (position1->r + offset->r), 3);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->d, (position1->d + offset->d), 4);
-            psFree(position2);
-
-            tmpOffset->r = RAD_TO_MIN(offset->r);
-            tmpOffset->d = RAD_TO_MIN(offset->d);
-            tmpOffset->rErr = 0.0;
-            tmpOffset->dErr = 0.0;
-            position2 = psSphereSetOffset(position1, tmpOffset, PS_SPHERICAL, PS_ARCMIN);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->r, (position1->r + offset->r), 5);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->d, (position1->d + offset->d), 6);
-            psFree(position2);
-
-            tmpOffset->r = RAD_TO_SEC(offset->r);
-            tmpOffset->d = RAD_TO_SEC(offset->d);
-            tmpOffset->rErr = 0.0;
-            tmpOffset->dErr = 0.0;
-            position2 = psSphereSetOffset(position1, tmpOffset, PS_SPHERICAL, PS_ARCSEC);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->r, (position1->r + offset->r), 7);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(position2->d, (position1->d + offset->d), 8);
-            psFree(position2);
-        }
-    }
-
-    // Attempt to call function with null input coordinate
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message null input coord");
-    position2 = psSphereSetOffset(NULL, offset, PS_LINEAR, PS_ARCSEC);
-    if (position2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL");
-        return 30;
-    }
-
-    // Attempt to call function with null offset
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message null offset");
-    position2 = psSphereSetOffset(position1, NULL, PS_LINEAR, PS_ARCSEC);
-    if (position2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL");
-        return 31;
-    }
-
-    // Attempt to call function with invalid mode
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message invalid mode");
-    position2 = psSphereSetOffset(position1, offset, 0x54321, 0);
-    if (position2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL");
-        return 32;
-    }
-
-    // Attempt to call function with invalid unit
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message invalid unit");
-    position2 = psSphereSetOffset(position1, offset, PS_SPHERICAL, 0x54321);
-    if (position2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL");
-        return 33;
-    }
-
-    psFree(position1);
-    psFree(offset);
-    psFree(tmpOffset);
-
-    return 0;
-}
-
-psS32 testSetOffsetLinear(void)
-{
-    psSphere*   coord = psSphereAlloc();
-    psSphere*   offset = psSphereAlloc();
-    psSphere*   out = NULL;
-
-    for(psS32 i = 0; i < TESTPOINTS_OFFSET; i++) {
-
-        coord->r = setOffsetTestpoint[i][0];
-        coord->d = setOffsetTestpoint[i][1];
-
-        offset->r = setOffsetOffset[i][0];
-        offset->d = setOffsetOffset[i][1];
-
-        out = psSphereSetOffset(coord, offset, PS_LINEAR, PS_RADIAN);
-
-        if(fabs(out->r - setOffsetResult[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d: Result out->r = %lg not equal to expected %lg",
-                    i, out->r, setOffsetResult[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->d - setOffsetResult[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d: Result out->d = %lg not equal to expected %lg",
-                    i,out->d, setOffsetResult[i][1]);
-            return i*10+2;
-        }
-
-        psFree(out);
-    }
-
-    psFree(coord);
-    psFree(offset);
-
-    return 0;
-}
-
-psS32 testGetOffsetSphere( void )
-{
-    psSphere* position1 = psSphereAlloc();
-    psSphere* position2 = psSphereAlloc();
-    psSphere *offset = NULL;
-
-    position1->r = DEG_TO_RAD(90.0);
-    position1->d = DEG_TO_RAD(45.0);
-    position1->rErr = 0.0;
-    position1->dErr = 0.0;
-
-    for (psF64 r = 0.0; r < 180.0;r += DEG_INC) {
-        for (psF64 d = 0.0;d < 90.0; d += DEG_INC) {
-            position2->r = DEG_TO_RAD(r);
-            position2->d = DEG_TO_RAD(d);
-            position2->rErr = 0.0;
-            position2->dErr = 0.0;
-
-            offset = psSphereGetOffset( position1,  position2,
-                                        PS_SPHERICAL, PS_RADIAN);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->r, (position2->r - position1->r), 1);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->d, (position2->d - position1->d), 1);
-            psFree(offset);
-
-            offset = psSphereGetOffset( position1, position2,
-                                        PS_SPHERICAL, PS_DEGREE);
-            offset->r = DEG_TO_RAD(offset->r);
-            offset->d = DEG_TO_RAD(offset->d);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->r, (position2->r - position1->r), 2);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->d, (position2->d - position1->d), 3);
-            psFree(offset);
-
-            offset = psSphereGetOffset( position1,  position2,
-                                        PS_SPHERICAL, PS_ARCMIN);
-            offset->r = MIN_TO_RAD(offset->r);
-            offset->d = MIN_TO_RAD(offset->d);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->r, (position2->r - position1->r), 2);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->d, (position2->d - position1->d), 3);
-            psFree(offset);
-
-            offset = psSphereGetOffset( position1,  position2,
-                                        PS_SPHERICAL, PS_ARCSEC);
-            offset->r = SEC_TO_RAD(offset->r);
-            offset->d = SEC_TO_RAD(offset->d);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->r, (position2->r - position1->r), 2);
-            PS_COMPARE_TINY_THEN_PRINT_ERROR(offset->d, (position2->d - position1->d), 3);
-            psFree(offset);
-        }
-    }
-
-    // Attempt to invoke function with null position 1 parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null position");
-    offset = psSphereGetOffset(NULL, position2, PS_LINEAR, 0);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 10;
-    }
-
-    // Attempt to invoke function with null position 2 parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for null position");
-    offset = psSphereGetOffset(position1, NULL, PS_LINEAR, 0);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 11;
-    }
-
-    // Attempt to invoke function with invalid mode
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid mode");
-    offset = psSphereGetOffset(position1, position2, 0x54321, 0);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 12;
-    }
-
-    // Attempt to invoke function with invalid unit type
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid unit type");
-    offset = psSphereGetOffset(position1, position2, PS_SPHERICAL, 0x54321);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 13;
-    }
-
-    // Attempt to invoke function with coordinate 1 declination value 90.0 degree
-    position1->d = DEG_TO_RAD(90.0);
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate warning message");
-    offset = psSphereGetOffset(position1, position2, PS_SPHERICAL, PS_RADIAN);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 14;
-    }
-
-    // Attempt to invoke function with coordinate 2 declination value 90.0 degree
-    position1->d = DEG_TO_RAD(45.0);
-    position2->d = DEG_TO_RAD(90.0);
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate warning message");
-    offset = psSphereGetOffset(position1, position2, PS_SPHERICAL, PS_RADIAN);
-    if (offset != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 15;
-    }
-
-    psFree(position1);
-    psFree(position2);
-
-    return 0;
-}
-
-psS32 testGetOffsetLinear(void)
-{
-    psSphere*   coord1 = psSphereAlloc();
-    psSphere*   coord2 = psSphereAlloc();
-    psSphere*   out = NULL;
-
-    for(psS32 i = 0; i < TESTPOINTS_OFFSET; i++) {
-
-        coord1->r = getOffsetTestpoint1[i][0];
-        coord1->d = getOffsetTestpoint1[i][1];
-
-        coord2->r = getOffsetTestpoint2[i][0];
-        coord2->d = getOffsetTestpoint2[i][1];
-
-        out = psSphereGetOffset(coord1, coord2, PS_LINEAR, PS_RADIAN);
-
-        if(fabs(out->r - getOffsetResult[i][0]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d: Result out->r = %lg not equal to expected %lg",
-                    i, out->r, getOffsetResult[i][0]);
-            return i*10+1;
-        }
-        if(fabs(out->d - getOffsetResult[i][1]) > ERROR_TOL) {
-            psError(PS_ERR_UNKNOWN,true,"Testpoint %d: Result out->d = %lg not equal to expected %lg",
-                    i,out->d, getOffsetResult[i][1]);
-            return i*10+2;
-        }
-
-        psFree(out);
-    }
-
-    psFree(coord1);
-    psFree(coord2);
-
-    return 0;
-}
-
-#define DEG_INC2 15.0
-#define VERBOSE 0
-psS32 testProjectTanDeProjectTan()
-{
-    psS32 rc = 0;
-    //
-    // I'm not convinced that the p_psProject() and p_psDeproject() functions work
-    // correctly.  If we project a set of coordinates over a wide range of (R, D)
-    // values, then deproject them, the original (R, D) values are only produced
-    // when D is larger than 0.  This code demonstrates that.
-    //
-    psProjection *tmpProj = psProjectionAlloc(0.0,0.0,10.0,10.0,PS_PROJ_TAN);
-    if (1) { //HEY
-        psPlane planeCoord01;
-        psSphere skyCoord01;
-        psSphere skyCoord02;
-        for (psF32 R = -90.0 ; R <= 90.0 ; R+= DEG_INC2) {
-            for (psF32 D = -90.0 ; D <= 90.0 ; D+= DEG_INC2) {
-                if ((fabs(R) != 90.0) && (fabs(D) != 90.0)) {
-                    skyCoord01.r = DEG_TO_RAD(R);
-                    skyCoord01.d = DEG_TO_RAD(D);
-                    p_psProject(&planeCoord01, &skyCoord01, tmpProj);
-                    p_psDeproject(&skyCoord02, &planeCoord01, tmpProj);
-                    if ((fabs(skyCoord01.r - skyCoord02.r) < FLT_EPSILON) &&
-                            (fabs(skyCoord01.d - skyCoord02.d) < FLT_EPSILON)) {
-                        if (VERBOSE) {
-                            printf("CORRECT: (%.2fr %.2fd) (%.2fr %.2fd) -> (%.2f %.2f) -> (%.2fr %.2fd)\n", R, D,
-                                   skyCoord01.r, skyCoord01.d,
-                                   planeCoord01.x, planeCoord01.y,
-                                   skyCoord02.r, skyCoord02.d);
-                        }
-                        rc = 1;
-                    } else {
-                        printf("TEST ERROR: (%.2fr %.2fd) (%.2fr %.2fd) -> (%.2f %.2f) -> (%.2fr %.2fd)\n", R, D,
-                               skyCoord01.r, skyCoord01.d,
-                               planeCoord01.x, planeCoord01.y,
-                               skyCoord02.r, skyCoord02.d);
-                        rc = 1;
-                    }
-                }
-            }
-        }
-    }
-    return(rc);
-}
-
-
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psCoord02.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psCoord02.c	(revision 30117)
+++ 	(revision )
@@ -1,572 +1,0 @@
-/** @file  tst_psCoord02.c
-*
-*  @brief This file contains test code for:
-*
-*  @author GLG, MHPCC
-*
-*  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-02-17 03:24:46 $
-*
-*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
-*/
-
-#include "psTest.h"
-#include "pslib_strict.h"
-
-static psS32 test04( void );
-static psS32 test05( void );
-static psS32 test06( void );
-static psS32 test07( void );
-
-testDescription tests[] = {
-                              {test04, 660, "psPlaneTransformCombine()", 0, false},
-                              {test05, 662, "psPlaneTransformFit()", 0, false},
-                              {test06, 663, "psPlaneTransformInvert()", 0, false},
-                              {test07, 666, "psPlaneTransformDeriv()", 0, false},
-                              {NULL}
-                          };
-
-#define PS_PERCENT_COMPARE(X, Y, PERCENT_FRACTION) (fabs((Y)-(X))/fabs(X) < (PERCENT_FRACTION))
-
-//#define PS_GEN_RAN_FLOAT (-1.0 + (psF32) (rand() % 2))
-#define PS_GEN_RAN_FLOAT (-0.5 + ((psF32)rand()) / ((psF32) RAND_MAX))
-#define RANDOM_SEED 1995
-
-psS32 main( psS32 argc, char* argv[] )
-{
-    psLogSetLevel( PS_LOG_INFO );
-    psLogSetFormat("HLNM");
-    psTraceSetLevel(".", 0);
-    psTraceSetLevel("psPlaneTransformCombine", 0);
-    psTraceSetLevel("multiplyDPoly2D", 0);
-    srand(RANDOM_SEED);
-
-    return ( ! runTestSuite( stderr, "psImage", tests, argc, argv ) );
-}
-
-
-/******************************************************************************
-TEST04: The strategy behind test04() is to generate a pair of transforms t1
-and t2 with a wide variety of sizes for the x/y components of the x/y
-transforms, then set the coefficients of t1/t2 to arbitray values, then
-generate a new transform t3 via psPlaneTransformCombine() function.  Then, for
-several arbitrary input plane coordinates, we tarnsform them via the new
-transform t3, as well as individually via t1 then t2, and verify that they
-produce identical output coordinates.
- *****************************************************************************/
-// These macros determine the number of x/y test points which will be x-formed.
-#define TST04_X_MIN 0.0
-#define TST04_X_MAX 10.0
-#define TST04_Y_MIN 0.0
-#define TST04_Y_MAX 10.0
-#define TST04_NUM 5.0
-// These macros define the max sizes of the various input transforms.
-#define TST04_T1_X_X 2
-#define TST04_T1_X_Y 3
-#define TST04_T1_Y_X 3
-#define TST04_T1_Y_Y 3
-#define TST04_T2_X_X 3
-#define TST04_T2_X_Y 3
-#define TST04_T2_Y_X 3
-#define TST04_T2_Y_Y 3
-/******************************************************************************
-tstTransforms(t1, t2, t3): this function generates a set of arbitrary x/y
-coordinates, then transforms them into output coordinates via the t3
-transform, as well as the t1 followed by the t2 transform.  It verifies the
-output coordinates are identical and returns TRUE if so.  Otherwise, it prints
-an error message and returns FALSE.
- *****************************************************************************/
-bool tstTransforms(psPlaneTransform *t1, psPlaneTransform *t2, psPlaneTransform *t3)
-{
-    bool testStatus = true;
-    psPlane *in = psPlaneAlloc();
-    in->xErr = 0.0;
-    in->yErr = 0.0;
-
-    for (in->x = TST04_X_MIN ; in->x <= TST04_X_MAX ; in->x+= (TST04_X_MAX-TST04_X_MIN) / TST04_NUM) {
-        for (in->y = TST04_Y_MIN ; in->y <= TST04_Y_MAX ; in->y+= (TST04_Y_MAX-TST04_Y_MIN) / TST04_NUM) {
-            // Apply the t1/t2 transforms individually to the in coords.
-            psPlane *mid = psPlaneTransformApply(NULL, t1, in);
-            if (mid == NULL) {
-                printf("TEST ERROR: intermediate psPlane coords are NULL.\n");
-                psFree(in);
-                return(false);
-            }
-
-            psPlane *outT1T2 = psPlaneTransformApply(NULL, t2, mid);
-            if (outT1T2 == NULL) {
-                printf("TEST ERROR: intermediate psPlane coords are NULL.\n");
-                psFree(mid);
-                return(false);
-            }
-
-            // Apply the t3 transforms individually to the in coords.
-            psPlane *outT3 = psPlaneTransformApply(NULL, t3, in);
-            if (outT3 == NULL) {
-                printf("TEST ERROR: intermediate psPlane coords are NULL.\n");
-                psFree(mid);
-                psFree(outT1T2);
-                return(false);
-            }
-
-            // Verify that the results are identical.
-            if (!PS_PERCENT_COMPARE(outT3->x, outT1T2->x, 0.01)) {
-                printf("TEST ERROR: x is %f, should be %f\n", outT3->x, outT1T2->x);
-                testStatus = false;
-            }
-            // Verify that the results are identical.
-            if (!PS_PERCENT_COMPARE(outT3->y, outT1T2->y, 0.01)) {
-                printf("TEST ERROR: y is %f, should be %f\n", outT3->y, outT1T2->y);
-                testStatus = false;
-            }
-            if (0) {
-                if (fabs(outT3->x - outT1T2->x) > FLT_EPSILON) {
-                    printf("TEST ERROR: x is %f, should be %f\n", outT3->x, outT1T2->x);
-                    testStatus = false;
-                    printf("(in->x, in->y) is (%f, %f)\n", in->x, in->y);
-                    printf("(mid->x, mid->y) is (%f, %f)\n", mid->x, mid->y);
-                    printf("(outT1T2->x, outT1T2->y) is (%f, %f)\n", outT1T2->x, outT1T2->y);
-                    printf("(outT3->x, outT3->y) is (%f, %f)\n", outT3->x, outT3->y);
-                    PS_POLY_PRINT_2D(t1->x);
-                    PS_POLY_PRINT_2D(t1->y);
-                    PS_POLY_PRINT_2D(t2->x);
-                    PS_POLY_PRINT_2D(t2->y);
-                    PS_POLY_PRINT_2D(t3->x);
-                    PS_POLY_PRINT_2D(t3->y);
-                }
-                if (fabs(outT3->y - outT1T2->y) > FLT_EPSILON) {
-                    printf("TEST ERROR: y is %f, should be %f\n", outT3->y, outT1T2->y);
-                    testStatus = false;
-                    printf("(in->x, in->y) is (%f, %f)\n", in->x, in->y);
-                    printf("(mid->x, mid->y) is (%f, %f)\n", mid->x, mid->y);
-                    printf("(outT1T2->x, outT1T2->y) is (%f, %f)\n", outT1T2->x, outT1T2->y);
-                    printf("(outT3->x, outT3->y) is (%f, %f)\n", outT3->x, outT3->y);
-                    PS_POLY_PRINT_2D(t1->x);
-                    PS_POLY_PRINT_2D(t1->y);
-                    PS_POLY_PRINT_2D(t2->x);
-                    PS_POLY_PRINT_2D(t2->y);
-                    PS_POLY_PRINT_2D(t3->x);
-                    PS_POLY_PRINT_2D(t3->y);
-                }
-            }
-            psFree(mid);
-            psFree(outT1T2);
-            psFree(outT3);
-        }
-    }
-
-    psFree(in);
-    return(testStatus);
-}
-
-/******************************************************************************
-setCoeffs(t1, t2): this function sets the coefficients of the t1 and t2
-transforms to somewhat arbitrary values.
- *****************************************************************************/
-int setCoeffs(psPlaneTransform *t1, psPlaneTransform *t2)
-{
-    for (psS32 t1xx = 0 ; t1xx < t1->x->nX+1 ; t1xx++) {
-        for (psS32 t1xy = 0 ; t1xy < t1->x->nY+1 ; t1xy++) {
-            t1->x->coeff[t1xx][t1xy] = PS_GEN_RAN_FLOAT;
-            //printf("%f\n", t1->x->coeff[t1xx][t1xy]);
-        }
-    }
-
-    for (psS32 t1yx = 0 ; t1yx < t1->y->nX+1 ; t1yx++) {
-        for (psS32 t1yy = 0 ; t1yy < t1->y->nY+1 ; t1yy++) {
-            t1->y->coeff[t1yx][t1yy] = PS_GEN_RAN_FLOAT;
-            //printf("%f\n", t1->y->coeff[t1yx][t1yy]);
-        }
-    }
-    for (psS32 t2xx = 0 ; t2xx < t2->x->nX+1 ; t2xx++) {
-        for (psS32 t2xy = 0 ; t2xy < t2->x->nY+1 ; t2xy++) {
-            t2->x->coeff[t2xx][t2xy] = PS_GEN_RAN_FLOAT;
-            //printf("%f\n", t2->x->coeff[t2xx][t2xy]);
-        }
-    }
-    for (psS32 t2yx = 0 ; t2yx < t2->y->nX+1 ; t2yx++) {
-        for (psS32 t2yy = 0 ; t2yy < t2->y->nY+1 ; t2yy++) {
-            t2->y->coeff[t2yx][t2yy] = PS_GEN_RAN_FLOAT;
-            //printf("%f\n", t2->y->coeff[t2yx][t2yy]);
-        }
-    }
-
-    return(0);
-}
-
-/******************************************************************************
-test04(): We test psPlaneTransformCombine() with a variety of input
-transforms, as well as input coordinates, as well as erroneous input
-parameters.
- *****************************************************************************/
-psS32 test04( void )
-{
-    bool testStatus = true;
-
-    //HEY
-    // Create a variety of input transforms, then test them.
-    //
-    for (psS32 t1xx = 0 ; t1xx < TST04_T1_X_X ; t1xx++) {
-        for (psS32 t1xy = 0 ; t1xy < TST04_T1_X_Y ; t1xy++) {
-            for (psS32 t1yx = 0 ; t1yx < TST04_T1_Y_X ; t1yx++) {
-                for (psS32 t1yy = 0 ; t1yy < TST04_T1_Y_Y ; t1yy++) {
-                    for (psS32 t2xx = 0 ; t2xx < TST04_T2_X_X ; t2xx++) {
-                        for (psS32 t2xy = 0 ; t2xy < TST04_T2_X_Y ; t2xy++) {
-                            for (psS32 t2yx = 0 ; t2yx < TST04_T2_Y_X ; t2yx++) {
-                                for (psS32 t2yy = 0 ; t2yy < TST04_T2_Y_Y ; t2yy++) {
-                                    //printf("(%d %d %d %d %d %d %d %d)\n", t1xx, t1xy, t1yx, t1yy, t2xx, t2xy, t2yx, t2yy);
-                                    psPlaneTransform *trans1 = psPlaneTransformAlloc(PS_MAX(t1xx, t1yx), PS_MAX(t1xy, t1yy));
-                                    psPlaneTransform *trans2 = psPlaneTransformAlloc(PS_MAX(t2xx, t2yx), PS_MAX(t2xy, t2yy));
-                                    psPlaneTransform *trans3 = NULL;
-                                    setCoeffs(trans1, trans2);
-                                    trans3 = psPlaneTransformCombine(NULL, trans1,
-                                                                     trans2, psRegionSet(NAN,NAN,NAN,NAN), 0);
-                                    //XXX: the last two parameters are bogus.  Needs to change.  -rdd
-
-                                    if (trans3 == NULL) {
-                                        printf("TEST ERROR: psPlaneTransformCombine() returned NULL/\n");
-                                        testStatus = false;
-                                    } else {
-                                        testStatus = tstTransforms(trans1, trans2, trans3);
-                                    }
-                                    psFree(trans1);
-                                    psFree(trans2);
-                                    psFree(trans3);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-
-    //
-    // Test erroneous input parameter combinations
-    //
-    psPlaneTransform *trans1 = psPlaneTransformAlloc(2, 2);
-    psPlaneTransform *trans2 = psPlaneTransformAlloc(2, 2);
-    psPlaneTransform *trans3 = NULL;
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformCombine with NULL trans1.  Should generate error and return NULL.\n");
-    trans3 = psPlaneTransformCombine(NULL, NULL, trans2, psRegionSet(0,0,0,0), 10);
-    if (trans3 != NULL) {
-        printf("TEST ERROR: psPlaneTransformCombine() returned a non-NULL psPlaneTransform.\n");
-        testStatus = false;
-        psFree(trans3);
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformCombine with NULL trans2.  Should generate error and return NULL.\n");
-    trans3 = psPlaneTransformCombine(NULL, trans1, NULL, psRegionSet(0,0,0,0), 10);
-    if (trans3 != NULL) {
-        printf("TEST ERROR: psPlaneTransformCombine() returned a non-NULL psPlaneTransform.\n");
-        testStatus = false;
-        psFree(trans3);
-    }
-
-    psFree(trans1);
-    psFree(trans2);
-    return(!testStatus);
-}
-
-
-#define TST05_X_MIN 0.0
-#define TST05_X_MAX 10.0
-#define TST05_Y_MIN 0.0
-#define TST05_Y_MAX 10.0
-#define TST05_NUM_X 5.0
-#define TST05_NUM_Y 5.0
-#define TST05_X_POLY_ORDER 3
-#define TST05_Y_POLY_ORDER 3
-#define TST05_NUM_DATA (TST05_NUM_X * TST05_NUM_Y)
-#define TST05_IGNORE 1
-#define TST05_VERBOSE 0
-/******************************************************************************
-XXX: This is only a rudimentary test of the psPlaneTransformFit() function.
-It tests a few NULL input parameter conditions, and some simple linear
-transformations.
- 
-// HEY
- *****************************************************************************/
-psS32 test05( void )
-{
-    bool testStatus = true;
-    psPlaneTransform *trans = psPlaneTransformAlloc(TST05_X_POLY_ORDER, TST05_Y_POLY_ORDER);
-    psPlaneTransform *transInit = psPlaneTransformAlloc(TST05_X_POLY_ORDER, TST05_Y_POLY_ORDER);
-    psArray *src = psArrayAlloc((int) TST05_NUM_DATA);
-    psArray *dst = psArrayAlloc((int) TST05_NUM_DATA);
-    bool rc;
-
-    //
-    // We set an arbitrary non-linear transformation.
-    //
-    for (psS32 x = 0 ; x < TST05_X_POLY_ORDER+1 ; x++) {
-        for (psS32 y = 0 ; y < TST05_Y_POLY_ORDER+1 ; y++) {
-            transInit->x->coeff[x][y] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            transInit->y->coeff[x][y] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-        }
-    }
-    if (TST05_VERBOSE) {
-        PS_POLY_PRINT_2D(transInit->x);
-        PS_POLY_PRINT_2D(transInit->y);
-    }
-
-    //
-    // We generate a grid of input data points in the x1,y1 plane, calculate the
-    // corresponding values in the transformed plane, and set these to
-    // the src and dst psVectors.
-    //
-    psS32 i = 0;
-    for (psF32 x = TST05_X_MIN ; x < TST05_X_MAX ; x+= (TST05_X_MAX-TST05_X_MIN)/TST05_NUM_X) {
-        for (psF32 y = TST05_Y_MIN ; y < TST05_Y_MAX ; y+= (TST05_Y_MAX-TST05_Y_MIN)/TST05_NUM_Y) {
-            if (i == src->n) {
-                if (src->n == src->nalloc) {
-                    src = psArrayRealloc(src, src->n+1);
-                }
-                src->n++;
-            }
-            if (i == dst->n) {
-                if (dst->n == dst->nalloc) {
-                    dst = psArrayRealloc(dst, dst->n+1);
-                }
-                dst->n++;
-            }
-            src->data[i] = (psPtr *) psPlaneAlloc();
-            ((psPlane *) src->data[i])->x = x;
-            ((psPlane *) src->data[i])->y = y;
-
-            dst->data[i] = psPlaneTransformApply(NULL, transInit, ((psPlane *) src->data[i]));
-            i++;
-        }
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformFit with NULL trans.  Should generate error and return NULL.\n");
-    rc = psPlaneTransformFit(NULL, src, dst, 100, 100.0);
-    if (rc == true) {
-        printf("TEST ERROR1: psPlaneTransformFit() returned TRUE.\n");
-        testStatus = false;
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformFit with NULL src psArray.  Should generate error and return NULL.\n");
-    rc = psPlaneTransformFit(trans, NULL, dst, 100, 100.0);
-    if (rc == true) {
-        printf("TEST ERROR2: psPlaneTransformFit() returned TRUE.\n");
-        testStatus = false;
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformFit with NULL dst psArray.  Should generate error and return NULL.\n");
-    rc = psPlaneTransformFit(trans, src, NULL, 100, 100.0);
-    if (rc == true) {
-        printf("TEST ERROR3: psPlaneTransformFit() returned TRUE.\n");
-        testStatus = false;
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformFit with acceptable data.\n");
-    rc = psPlaneTransformFit(trans, src, dst, 100, 100.0);
-    if (rc != true) {
-        printf("TEST ERROR4: psPlaneTransformFit() returned FALSE.\n");
-        testStatus = false;
-    } else {
-        if (TST05_VERBOSE) {
-            PS_POLY_PRINT_2D(trans->x);
-            PS_POLY_PRINT_2D(trans->y);
-        }
-
-        //
-        // For the initial grid of input points, we transform them to output points with
-        // the derived transformation, and verify that they are within 10%.
-        //
-
-        for (psS32 i = TST05_IGNORE ; i < src->n-TST05_IGNORE ; i++) {
-            psPlane *inData = (psPlane *) src->data[i];
-            psPlane *outData = (psPlane *) dst->data[i];
-            psPlane *outDataDeriv = psPlaneTransformApply(NULL, trans, inData);
-            if (!PS_PERCENT_COMPARE(outDataDeriv->x, outData->x, 0.20) ||
-                    !PS_PERCENT_COMPARE(outDataDeriv->y, outData->y, 0.20)) {
-                printf("TEST ERROR: the derived output coords (%d) were (%.2f, %.2f) should have been (%.2f, %.2f).\n",
-                       i, outDataDeriv->x, outDataDeriv->y, outData->x, outData->y);
-                testStatus = false;
-            } else if (TST05_VERBOSE) {
-                printf("GOOD: the derived output coords (%d) were (%.2f, %.2f) should have been (%.2f, %.2f).\n",
-                       i, outDataDeriv->x, outDataDeriv->y, outData->x, outData->y);
-            }
-            psFree(outDataDeriv);
-        }
-    }
-
-    psFree(transInit);
-    psFree(trans);
-    psFree(src);
-    psFree(dst);
-
-    return(!testStatus);
-}
-
-#define NUM_TRANSFORMS 100
-/******************************************************************************
-This is only a rudimentary test of the psPlaneTransformInvert() function.
-It tests:
-    A few NULL input parameter conditions.
-    Several random linear transformations.
-XXX: Must extensively test:
-    Non-linear transformations.
-  *****************************************************************************/
-psS32 test06( void )
-{
-    bool testStatus = true;
-    psPlaneTransform *trans = psPlaneTransformAlloc(1, 1);
-    psPlaneTransform *transInverse = NULL;
-    psRegion myRegion = psRegionSet(1.0, 5.0, 1.0, 5.0);
-
-    trans->x->coeff[0][0] = 0.0;
-    trans->x->coeff[0][1] = 1.0;
-    trans->x->coeff[1][0] = 2.0;
-    trans->x->coeff[1][1] = 3.0;
-    trans->y->coeff[0][0] = 4.0;
-    trans->y->coeff[0][1] = 5.0;
-    trans->y->coeff[1][0] = 6.0;
-    trans->y->coeff[1][1] = 7.0;
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformInvert with NULL trans.  Should generate error and return NULL.\n");
-    transInverse = psPlaneTransformInvert(NULL, NULL, myRegion, 10);
-    if (transInverse != NULL) {
-        printf("TEST ERROR: psPlaneTransformInvert() returned a non-NULL psPlaneTransform.\n");
-        testStatus = false;
-        psFree(transInverse);
-    }
-
-    printf("----------------------------------------------------------------------------------\n");
-    printf("Calling psPlaneTransformInvert with zero nSamples.  Should generate error and return NULL.\n");
-    transInverse = psPlaneTransformInvert(NULL, trans, myRegion, 0);
-    if (transInverse != NULL) {
-        printf("TEST ERROR: psPlaneTransformInvert() returned a non-NULL psPlaneTransform.\n");
-        testStatus = false;
-        psFree(transInverse);
-    }
-
-    printf("Calling psPlaneTransformInvert with acceptable linear transformations.\n");
-    for (psS32 n = 0 ; n < NUM_TRANSFORMS ; n++) {
-        if (n == 0) {
-            // I ensure that we test the identity transformation since this was
-            // giving us probs before.
-            trans->x->coeff[0][0] = 0.0;
-            trans->x->coeff[0][1] = 0.0;
-            trans->x->coeff[1][0] = 1.0;
-            trans->x->coeff[1][1] = 0.0;
-            trans->y->coeff[0][0] = 0.0;
-            trans->y->coeff[0][1] = 1.0;
-            trans->y->coeff[1][0] = 0.0;
-            trans->y->coeff[1][1] = 0.0;
-        } else {
-            // We create a random linear transformation and hope it is invertible.
-            trans->x->coeff[0][0] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->x->coeff[0][1] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->x->coeff[1][0] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->x->coeff[1][1] = 0.0;
-            trans->y->coeff[0][0] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->y->coeff[0][1] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->y->coeff[1][0] = (psF32)rand() / (psF32)RAND_MAX * 10.0f;
-            trans->y->coeff[1][1] = 0.0;
-        }
-
-        transInverse = psPlaneTransformInvert(NULL, trans, myRegion, 10);
-        if (transInverse == NULL) {
-            printf("TEST ERROR: psPlaneTransformInvert() returned a NULL psPlaneTransform.\n");
-            testStatus = false;
-        }
-        //
-        // Transform the "in" coords to "mid" with psPlaneTransform "trans", then
-        // transform "mid" to "out" with psPlaneTransform "transInverse".
-        //
-        // XXX: Loop on a few data points.
-        //
-        psPlane *in = psPlaneAlloc();
-        in->x = 2.0;
-        in->y = 3.0;
-        psPlane *mid = psPlaneTransformApply(NULL, trans, in);
-        psPlane *out = psPlaneTransformApply(NULL, transInverse, mid);
-
-        if (((fabs(in->x - out->x) > FLT_EPSILON)) ||
-                ((fabs(in->y - out->y) > FLT_EPSILON)) ||
-                isnan(out->x) ||
-                isnan(out->y)) {
-            printf("TEST ERROR: in coords were (%f, %f), out coords were (%f, %f).\n",
-                   in->x, in->y, out->x, out->y);
-            testStatus = false;
-        }
-
-        psFree(in);
-        psFree(mid);
-        psFree(out);
-        psFree(transInverse);
-    }
-
-    psFree(trans);
-
-    fflush(stdout);
-
-    return(!testStatus);
-}
-
-psS32 test07( void )
-{
-    psPlane *coord = psPlaneAlloc();
-    psPlane *deriv = NULL;
-    psPlaneTransform *trans = NULL;
-
-    //Set fxn values for evaluation
-    coord->x = 3.0;
-    coord->y = 1.0;
-
-    //Return NULL for NULL input plane transform
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    deriv = psPlaneTransformDeriv(NULL, trans, coord);
-    if (deriv != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psPlaneTransformDeriv failed to return NULL for NULL plane transform input.\n");
-        return 1;
-    }
-
-    trans = psPlaneTransformAlloc(1, 3);
-
-    //Set Polynomials.  f(x) = x, f(y) = 0.5*y^2  -->  f'(x) = 1, f'(y) = y
-    //So for 1,1  -> f'(1) = 1, f'(1) = 1
-    trans->x->coeff[0][0] = 0.0;
-    trans->x->coeff[1][0] = 1.0;
-    trans->y->coeff[0][0] = 0.0;
-    trans->y->coeff[0][1] = 0.0;
-    trans->y->coeff[0][2] = 0.5;
-
-    //Return NULL for NULL input plane
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    deriv = psPlaneTransformDeriv(NULL, trans, NULL);
-    if (deriv != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psPlaneTransformDeriv failed to return NULL for NULL plane input.\n");
-        return 2;
-    }
-
-    //Return correct values.  Should have x=1.0, y=1.0.
-    deriv = psPlaneTransformDeriv(NULL, trans, coord);
-    if (deriv->x != 1.0 || deriv->y != 1.0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psPlaneTransformDeriv failed to return the correct values.\n");
-        printf("\n f' values are = %lf, %lf \n", deriv->x, deriv->y);
-        return 3;
-    }
-
-    psFree(trans);
-    psFree(deriv);
-    psFree(coord);
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psEarthOrientation.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psEarthOrientation.c	(revision 30117)
+++ 	(revision )
@@ -1,1205 +1,0 @@
-/** @file  tst_psEarthOrientation.c
-*
-*  @brief The code will perform earth orientation calculations and sphere rotations.
-*
-*  @author d-Rob, MHPCC
-*
-*  @version $Revision: 1.35 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-05-26 01:23:41 $
-*
-*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
-*/
-
-#include "psTest.h"
-#include "pslib_strict.h"
-
-
-static psS32 testAberration(void);
-static psS32 testGravityDeflect(void);
-static psS32 testEOCPrecession(void);
-static psS32 testEOCPrecessionCorr(void);
-static psS32 testEOCPolar(void);
-static psS32 testEOCPolarTide(void);
-static psS32 testEOCNutation(void);
-static psS32 testSphereRot_TEOtoCEO(void);
-static psS32 testSphereRot_CEOtoGCRS(void);
-static psS32 testSphereRot_ITRStoTEO(void);
-static psS32 testSphereRotPrecess(void);
-
-testDescription tests[] = {
-                              {testAberration, 666, "psAberration()", 0, false},
-                              {testGravityDeflect, 667, "psGravityDeflect()", 0, false},
-                              {testEOCPrecession, 669, "psEOCPrecession()", 0, false},
-                              {testEOCPrecessionCorr, 670, "psEOCPrecessionCorr()", 0, false},
-                              {testEOCPolar, 671, "psEOCPolar()", 0, false},
-                              {testEOCPolarTide, 672, "psEOCPolarTide()", 0, false},
-                              {testEOCNutation, 673, "psEOCNutation()", 0, false},
-                              {testSphereRot_TEOtoCEO, 674, "psSphereRot_TEOtoCEO()", 0, false},
-                              {testSphereRot_CEOtoGCRS, 675, "psSphereRot_CEOtoGCRS()", 0, false},
-                              {testSphereRot_ITRStoTEO, 676, "psSphereRRot_ITRStoTEO()", 0, false},
-                              {testSphereRotPrecess, 677, "psSphereRotPrecess()", 0, false},
-                              {NULL}
-                          };
-
-psS32 main( psS32 argc, char* argv[] )
-{
-    psLogSetLevel( PS_LOG_INFO );
-
-    // Initialize library internal structures
-    psLibInit("pslib.config");
-
-    if( !runTestSuite(stderr,"psEarthOrientation",tests,argc,argv)) {
-        return 1;
-    }
-
-    // Cleanup library
-    psLibFinalize();
-
-    return 0;
-
-    //    return ( ! runTestSuite( stderr, "psEarthOrientation", tests, argc, argv ) );
-}
-
-#define timesec 1049160600
-#define objR DEG_TO_RAD(122.9153182445501)
-#define objD DEG_TO_RAD(48.562968978679194)
-#define VERBOSE 0
-static psSphere *obj = NULL;
-static void objSetup(void);
-static double greatCircle(psSphere *in1, psSphere *in2);
-
-static void objSetup(void)
-{
-    if (obj == NULL) {
-        //        obj = psSphereAlloc();
-        //        obj->r = objR;
-        //        obj->d = objD;
-        psCube *tempCube = psCubeAlloc();
-        tempCube->x = -0.3598480726985338;
-        tempCube->y = 0.5555012823608123;
-        tempCube->z = 0.7496183628158023;
-        obj = psCubeToSphere(tempCube);
-        psFree(tempCube);
-    }
-}
-
-//returns the great circle ANGULAR distance between 2 positions (psSphere's)
-static double greatCircle(psSphere *in1, psSphere *in2)
-{
-    double r1, r2, d1, d2;
-    d1 = in1->r;
-    d2 = in2->r;
-    r1 = in1->d;
-    r2 = in2->d;
-    double out = 0.0;
-    double c1, c2, cd, s1, s2, sum, ac;
-    c1 = cos(r1);
-    c2 = cos(r2);
-    cd = cos(d1-d2);
-    s1 = sin(r1);
-    s2 = sin(r2);
-    sum = c1*c2*cd + s1*s2;
-    if (sum > 1.0)
-        sum = 1.0 - (sum - 1.0);
-
-    ac = acos(sum);
-    out = ac;
-    //    printf("\n  c1=%lf, c2=%lf, cd=%lf, s1=%lf, s2=%lf, sum=%.19g, ac=%g\n", c1,c2,cd,s1,s2,sum,ac);
-    //    out = acos(cos(r1)*cos(r2)*cos(d1-d2) + sin(r1)*sin(r2));
-    //    if (out != 0.0) printf("\n   in greatCircle, out = %lf\n", out);
-    return out;
-}
-
-psS32 testAberration(void)
-{
-    psSphere *apparent = NULL;
-    psSphere *empty = NULL;
-    psCube *actualCube = psCubeAlloc();
-    //values from After gravity deflection//
-    actualCube->x = -0.35961949760293604;
-    actualCube->y = 0.5555613950298085;
-    actualCube->z = 0.7496835020836093;
-    psSphere *actual = psCubeToSphere(actualCube);
-    psCube *cubeDir = psCubeAlloc();
-    cubeDir->x = 5148.713262821658;
-    cubeDir->y = -26945.04752348012;
-    cubeDir->z = -11682.787302030947;
-    cubeDir->x += -357.6031690489248;
-    cubeDir->y += 248.46429758174693;
-    cubeDir->z += 0.09694774143797581;
-    psSphere *direction = psCubeToSphere(cubeDir);
-    double speed = sqrt(cubeDir->x*cubeDir->x + cubeDir->y*cubeDir->y + cubeDir->z*cubeDir->z);
-    double c = 299792458.0; // Speed of light in vacuum (src:NIST)   /* m/s */
-    speed /= c;
-
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    empty = psAberration(empty, apparent, direction, speed);
-    if (empty != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psAberration failed to return NULL for NULL actual input.\n");
-        return 1;
-    }
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    empty = psAberration(empty, actual, apparent, speed);
-    if (empty != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psAberration failed to return NULL for NULL direction input.\n");
-        return 2;
-    }
-
-    apparent = psAberration(apparent, actual, direction, speed);
-    psCube *outCube = psSphereToCube(apparent);
-    if (VERBOSE) {
-        printf("\n -- resultCube = x,y,z =     %.13g,      %.13g,    %.13g  -- \n",
-               outCube->x, outCube->y, outCube->z);
-    }
-    //expected cube values
-    double x, y, z;
-    x = -0.35963388069046304;
-    y = 0.5555192509816625;
-    z = 0.7497078321908413;
-
-    if (VERBOSE) {
-        printf(" -- expectedCube = x,y,z =   %.13g,     %.13g,    %.13g  -- \n", x, y, z);
-        printf("Cube Difference  =  x,y,z  = %.13g, %.13g, %.13g \n\n",
-               (x - outCube->x), (y - outCube->y), (z - outCube->z) );
-    }
-    psFree(actual);
-    actualCube->x = x;
-    actualCube->y = y;
-    actualCube->z = z;
-    actual = psCubeToSphere(actualCube);
-    double xxx = greatCircle(actual, apparent);
-    if (VERBOSE) {
-        printf("   The great circle angular distance between expected & result = %.13g\n",
-               xxx);
-    }
-    if ( fabs(x - outCube->x) > FLT_EPSILON || fabs(y - outCube->y) > FLT_EPSILON ||
-            fabs(z - outCube->z) > FLT_EPSILON ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psAberration returned incorrect values.\n");
-        //        printf("\nMagnitude of expected change = x,y,z = %.13g, %.13g, %.13g \n",
-        //               (actualCube->x - x), (actualCube->y - y), (actualCube->z - z) );
-        //        printf("Magnitude of actual change = x,y,z = %.13g, %.13g, %.13g \n",
-        //               (actualCube->x - outCube->x), (actualCube->y - outCube->y),
-        //               (actualCube->z - outCube->z) );
-        psFree(actual);
-        actualCube->x = x;
-        actualCube->y = y;
-        actualCube->z = z;
-        actual = psCubeToSphere(actualCube);
-        x = greatCircle(actual, apparent);
-        if (VERBOSE) {
-            printf("   The great circle angular distance between expected & result = %.13g\n",
-                   x);
-        }
-        return 3;
-    }
-
-    psFree(outCube);
-    psFree(actualCube);
-    psFree(cubeDir);
-    psFree(apparent);
-    psFree(actual);
-    psFree(direction);
-
-    return 0;
-}
-
-psS32 testGravityDeflect(void)
-{
-    psSphere *apparent = NULL;
-    psSphere *empty = NULL;
-    psCube *actualCube = psCubeAlloc();
-    actualCube->x = -0.3596195125758298;
-    actualCube->y = 0.5555613903455866;
-    actualCube->z = 0.7496834983724809;
-    psSphere *actual = psCubeToSphere(actualCube);
-    psCube *sunCube = psCubeAlloc();
-    sunCube->x = 1.467797790127511e11;
-    sunCube->y = 2.5880956908748722e10;
-    sunCube->z = 1.1220046291457653e10;
-    double sunLength = sqrt(sunCube->x*sunCube->x + sunCube->y*sunCube->y + sunCube->z*sunCube->z);
-    sunCube->x /= sunLength;
-    sunCube->y /= sunLength;
-    sunCube->z /= sunLength;
-    if (VERBOSE) {
-        printf("sunCube = x,y,z = %.13g, %.13g, %.13g\n",
-               sunCube->x, sunCube->y, sunCube->z);
-    }
-    psSphere *sun = psCubeToSphere(sunCube);
-    if (VERBOSE) {
-        printf("sunSphere  = r, d = %.13g, %.13g\n", sun->r, sun->d);
-    }
-    psCube *outCube = psCubeAlloc();
-
-    empty = psGravityDeflection(apparent, empty, sun);
-    if (empty != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                "psGravityDeflection Failed to return NULL for NULL actual input sphere.\n");
-        return 1;
-    }
-    empty = psGravityDeflection(apparent, actual, empty);
-    if (empty != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, true,
-                "psGravityDeflection Failed to return NULL for NULL sun input sphere.\n");
-        return 2;
-    }
-
-    apparent = psGravityDeflection(NULL, actual, sun);
-    //    apparent->r *= -1.0;
-    //    apparent->d *= -1.0;
-    psSphere *result2;
-    //    psSphere *result2 = psSphereSetOffset(actual, apparent, PS_SPHERICAL, PS_RADIAN);
-    //    psSphere *result = psSphereSetOffset(actual, apparent, PS_SPHERICAL, PS_RADIAN);
-    //    psSphere *result = psSphereGetOffset(apparent, actual, PS_SPHERICAL, PS_RADIAN);
-    if (VERBOSE) {
-        printf(" -- actualCube = x,y,z = %.13g, %.13g, %.13g  -- \n",
-               actualCube->x, actualCube->y, actualCube->z);
-    }
-    //    psCube *outCube = psSphereToCube(result);
-    //    printf(" -- resultCube = x,y,z = %.13g, %.13g, %.13g  -- \n",
-    //           outCube->x, outCube->y, outCube->z);
-    psCube *outCube2 = psSphereToCube(apparent);
-    if (VERBOSE) {
-        printf(" -- resultCube2= x,y,z = %.13g, %.13g, %.13g  -- \n",
-               outCube2->x, outCube2->y, outCube2->z);
-    }
-    double x, y, z;
-    x = -0.35961949760293604;
-    y = 0.5555613950298085;
-    z = 0.7496835020836093;
-
-    if (VERBOSE) {
-        printf(" -- expectCube = x,y,z = %.13g, %.13g, %.13g  -- \n\n", x, y, z);
-
-        //    if ( fabs(x - outCube->x) > DBL_EPSILON || fabs(y - outCube->y) > DBL_EPSILON ||
-        //            fabs(z - outCube->z) > DBL_EPSILON ) {
-        //        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-        //                "psGravityDeflection returned incorrect values.\n");
-        printf("expect-actual=  x,y,z  = %.13g, %.13g, %.13g \n",
-               (x - actualCube->x), (y - actualCube->y), (z - actualCube->z) );
-        printf("expect-result=  x,y,z  = %.13g, %.13g, %.13g \n",
-               (x - outCube2->x), (y - outCube2->y), (z - outCube2->z) );
-        printf("result-actual=  x,y,z  = %.13g, %.13g, %.13g \n",
-               (outCube2->x - actualCube->x), (outCube2->y - actualCube->y),
-               (outCube2->z - actualCube->z) );
-    }
-    //        return 1;
-    //    }
-    //    psFree(result2);
-    outCube2->x = x;
-    outCube2->y = y;
-    outCube2->z = z;
-    result2 = psCubeToSphere(outCube2);
-    //    psFree(result);
-    psSphere *result = psSphereGetOffset(actual, result2, PS_SPHERICAL, PS_RADIAN);
-    psFree(result2);
-    result2 = psSphereGetOffset(actual, apparent, PS_SPHERICAL, PS_RADIAN);
-    if (VERBOSE) {
-        printf("The apparent output sphere = r,d = %.13g, %.13g\n", result2->r, result2->d);
-        printf("The expected output sphere = r,d = %.13g, %.13g\n\n", result->r, result->d);
-    }
-    psFree(result2);
-
-    psFree(outCube);
-    psFree(outCube2);
-    psFree(sunCube);
-    psFree(actualCube);
-    psFree(result);
-    psFree(actual);
-    psFree(apparent);
-    psFree(sun);
-
-    return 0;
-}
-
-psS32 testEOCPrecession(void)
-{
-    psTime *empty = NULL;
-    psTime *time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = timesec;
-    time->nsec = 0;
-    time->leapsecond = false;
-
-    //Tests for Precession Model //
-    psEarthPole *pmodel = NULL;
-    //Return NULL for NULL time input
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    pmodel = psEOC_PrecessionModel(empty);
-    if (pmodel != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_PrecessionModel failed to return NULL for NULL time input.\n");
-        return 1;
-    }
-    //Return NULL for UT1 time input
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    psTime *UT1time = psTimeAlloc(PS_TIME_UT1);
-    pmodel = psEOC_PrecessionModel(UT1time);
-    if (pmodel != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_PrecessionModel failed to return NULL for UT1 input time.\n");
-        return 2;
-    }
-    psFree(UT1time);
-    //Check return values from valid precession input
-    pmodel = psEOC_PrecessionModel(time);
-    if ( pmodel == NULL ) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_PrecessionModel returned NULL for valid input.\n");
-        return 3;
-    } else {
-        double x, y, s;
-        x = 2.857175590089105e-4;
-        y = 2.3968739377734732e-5;
-        s = -1.3970066457904322e-8;
-        if ( fabs(pmodel->x - x) > FLT_EPSILON || fabs(pmodel->y - y) > FLT_EPSILON
-                || fabs(pmodel->s - s) > FLT_EPSILON) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "   psEOC_PrecessionModel return incorrect values.\n");
-            return 4;
-        }
-        if (VERBOSE) {
-            printf("\n  PrecessionModel output = x,y,s = %.13g,  %.13g,  %.13g\n",
-                   pmodel->x, pmodel->y, pmodel->s);
-            printf("  Expected output        = x,y,s = %.13g, %.13g,  %.13g\n", x, y, s);
-            printf("  A difference of:                 %.13g, %.13g, %.13g\n",
-                   (pmodel->x - x), (pmodel->y - y), (pmodel->s - s) );
-        }
-    }
-    psFree(pmodel);
-
-    psFree(time);
-    if (!p_psEOCFinalize() ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "EOC failed finalization!\n");
-        return 12;
-    }
-
-    return 0;
-}
-
-psS32 testEOCPrecessionCorr(void)
-{
-    psTime *empty = NULL;
-    psTime *time2 = psTimeAlloc(PS_TIME_UTC);
-    time2->sec = timesec;
-    time2->nsec = 0;
-    time2->leapsecond = false;
-    //    time2 = psTimeConvert(time2, PS_TIME_TAI);
-
-    //Tests for Precession Correction function//
-    //Return NULL for NULL time input
-    psEarthPole *pcorr = NULL;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    pcorr = psEOC_PrecessionCorr(empty, PS_IERS_A);
-    if (pcorr != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_PrecessionCorr failed to return NULL for NULL time input.\n");
-        return 5;
-    }
-
-    //Return NULL for Invalid IERS table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    pcorr = psEOC_PrecessionCorr(time2, 3);
-    if (pcorr != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_PrecessionCorr failed to return NULL for incorrect IERS table.\n");
-        return 6;
-    }
-    psFree(pcorr);
-
-    //Check values from IERS table A
-    pcorr = psEOC_PrecessionCorr(time2, PS_IERS_A);
-    if ( pcorr == NULL ) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_PrecessionCorr returned NULL for valid inputs.\n");
-        return 7;
-    } else {
-        if (VERBOSE) {
-            printf("\nPrecessionCorr output (IERSA) = x,y,s = %.13g,  %.13g, %.13g\n",
-                   pcorr->x, pcorr->y, pcorr->s);
-        }
-    }
-    psFree(pcorr);
-
-    //Check values from IERS table B
-    pcorr = psEOC_PrecessionCorr(time2, PS_IERS_B);
-    if ( pcorr == NULL ) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_PrecessionCorr returned NULL for valid inputs.\n");
-        return 9;
-    } else {
-        double xx, yy, ss;
-        xx = 0.06295703125;
-        yy = -0.0287618408203125;
-        ss = 0.0;
-        xx = SEC_TO_RAD(xx) * 1e-3;
-        yy = SEC_TO_RAD(yy) * 1e-3;
-        //        if ( fabs(pcorr->x - xx) > DBL_EPSILON || fabs(pcorr->y - yy) > DBL_EPSILON
-        //                || fabs(pcorr->s - ss) > DBL_EPSILON) {
-        //            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-        //                    "   psEOC_PrecessionCorr return incorrect values.\n");
-        if (VERBOSE) {
-            printf("PrecessionCorr output (IERSB) = x,y,s = %.13g, %.13g, %.13g\n",
-                   pcorr->x, pcorr->y, pcorr->s);
-            printf("Expected output               = x,y,s = %.13g, %.13g, %.13g\n", xx, yy, ss);
-            printf("          A difference of:              %.13g,  %.13g, %.13g\n\n",
-                   (pcorr->x - xx), (pcorr->y - yy), (pcorr->s - ss) );
-        }
-        //            return 10;
-        //        }
-    }
-    //precess is the *actual* output from PrecessionModel + PrecessionCorr
-    psEarthPole *precess = psEOC_PrecessionModel(time2);
-    precess->x += pcorr->x;
-    precess->y += pcorr->y;
-    double xCorr, yCorr;
-    xCorr = 3.05224300720406e-10;
-    yCorr = -1.39441339235822e-10;
-    //pcorr is the *expected* output from PrecessionModel//
-    pcorr->x = 2.857175590089105e-4;
-    pcorr->y = 2.3968739377734732e-5;
-    pcorr->s = -1.3970066457904322e-8;
-    pcorr->x += xCorr;
-    pcorr->y += yCorr;
-    psSphereRot *precessNutInv = psSphereRot_CEOtoGCRS(precess);
-    psSphereRot *precessNut = psSphereRotConjugate(NULL, precessNutInv);
-    double q0, q1, q2;
-    q0 = -1.1984522406756289e-5;
-    q1 = 1.4285893358610674e-4;
-    q2 = 1.2191193518914336e-10;
-    psSphereRot *pni = psSphereRot_CEOtoGCRS(pcorr);
-    if (fabs(pni->q0-q0) > FLT_EPSILON || fabs(pni->q1-q1) > FLT_EPSILON ||
-            fabs(pni->q2-q2) > FLT_EPSILON ) {
-        printf("\n Error at CEOtoGCRS, output psSphereRot doesn't match expected.\n");
-    }
-    //    printf("  Output from CEOtoGCRS only  = %.13g,%.13g,%.13g,%.13g\n",
-    //           pni->q0, pni->q1, pni->q2, pni->q3);
-    if (VERBOSE) {
-        printf("  Expected sphere rotation    = %.13g, %.13g, %.13g\n", q0,q1,q2);
-        printf("  Result sphere rotation      = %.13g, %.13g, %.13g\n",
-               precessNutInv->q0, precessNutInv->q1, precessNutInv->q2);
-        printf("     Difference         =        %.13g, %.13g, %.13g\n\n",
-               precessNutInv->q0-q0, precessNutInv->q1-q1, precessNutInv->q2-q2);
-    }
-    psCube *objC = psCubeAlloc();
-    //    objC->x = -3.5963388069046304;
-    //    objC->y = 0.5555192509816625;
-    //    objC->z = 0.7497078321908413;
-    //    objSetup();
-
-    //This is the sphere rotation for the *expected* precession output//
-    psSphereRot *pn = psSphereRotConjugate(NULL, pni);
-
-    //    psSphere *sphere = psSphereAlloc();
-    //    *sphere = *obj;
-    //    psFree(obj);
-
-    //create a psSphere for (from) the start position given in eoc_testing//
-    objC->x = -0.35963388069046304;
-    objC->y = 0.5555192509816625;
-    objC->z = 0.7497078321908413;
-    psSphere *sphere = psCubeToSphere(objC);
-
-    psSphere *expect = psSphereRotApply(NULL, pn, sphere);
-    //expected results below - stored in:  sphere  //
-    double x,y,z;
-    x = -0.3598480726985338;
-    y = 0.5555012823608123;
-    z = 0.7496183628158023;
-    if (VERBOSE) {
-        printf("\n<<Expected out       = x,y,z = %.13g, %.13g, %.13g\n", x, y, z);
-    }
-    //    psFree(objC);
-    //    objC = psSphereToCube(expect);
-    //printf("<<Expected out (CEO)  = x,y,z = %.13g, %.13g, %.13g\n", objC->x, objC->y, objC->z);
-    //printf("     Difference     =           %.13g, %.13g, %.13g\n", objC->x-x, objC->y-y, objC->z-z);
-    //    x = objC->x;
-    //    y = objC->y;
-    //    z = objC->z;
-    psSphere *result = psSphereRotApply(NULL, precessNut, sphere);
-    psFree(objC);
-    objC = psSphereToCube(result);
-    double xx = greatCircle(result, expect);
-    if (VERBOSE) {
-        printf("<<Resulting out      = x,y,z = %.13g, %.13g, %.13g\n", objC->x, objC->y, objC->z);
-        printf("     Difference         =      %.13g, %.13g, %.13g\n\n",
-               objC->x-x, objC->y-y, objC->z-z);
-        printf("GREAT CIRCLE DIFFERENCE = %.13g \n", xx);
-    }
-
-    psFree(precess);
-    psFree(precessNut);
-    psFree(precessNutInv);
-    psFree(expect);
-    psFree(objC);
-
-    psFree(sphere);
-    psFree(result);
-    psFree(pn);
-    psFree(pni);
-    psFree(pcorr);
-    psFree(time2);
-    if (!p_psEOCFinalize() ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "EOC failed finalization!\n");
-        return 12;
-    }
-
-    return 0;
-}
-
-psS32 testEOCPolar(void)
-{
-    psTime *in = psTimeAlloc(PS_TIME_UTC);
-    in->sec = timesec;
-    in->nsec = 0;
-    in->leapsecond = false;
-    psTime *empty = NULL;
-    psEarthPole *polarMotion = NULL;
-
-    //Return NULL for NULL input time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    polarMotion = psEOC_GetPolarMotion(empty, PS_IERS_B);
-    if (polarMotion != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_GetPolarMotion failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-    //Return NULL for incorrect Bulletin.
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    polarMotion = psEOC_GetPolarMotion(empty, 3);
-    if (polarMotion != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_GetPolarMotion failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-
-    //Test for IERS bulletin A.
-    double x, y, s;
-    x = -6.454389659777e-07;
-    y = 2.112606414597e-06;
-    s = 0.0;
-    polarMotion = psEOC_GetPolarMotion(in, PS_IERS_A);
-    if (polarMotion == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_GetPolarMotion returned NULL for valid input time.\n");
-        return 4;
-    }
-    //    if ( fabs(polarMotion->x - x) > DBL_EPSILON || fabs(polarMotion->y - y) > DBL_EPSILON
-    //            || fabs(polarMotion->s - s) > DBL_EPSILON) {
-    //        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-    //                "psEOC_GetPolarMotion returned incorrect values.\n");
-    if (VERBOSE) {
-        printf("  <>PolarMotion output (IERSA)   = x,y,s = %.13g, %.13g, %.13g\n",
-               polarMotion->x, polarMotion->y, polarMotion->s);
-    }
-    //        printf("  <>PolarMotion expected (IERSA) = x,y,s = %.13g, %.13g, %.13g\n",
-    //               x, y, s);
-    //        return 5;
-    //    }
-    psFree(polarMotion);
-
-    //Return valid values for correct input time.  Test IERS Bulletin B.
-    polarMotion = psEOC_GetPolarMotion(in, PS_IERS_B);
-    //    x = -6.45381397904e-07;
-    //    y = 2.112819726698e-06;
-    //    s = 0.0;
-    if (polarMotion == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_GetPolarMotion returned NULL for valid input time.\n");
-        return 2;
-    }
-    //    if ( fabs(polarMotion->x - x) > DBL_EPSILON || fabs(polarMotion->y - y) > DBL_EPSILON
-    //            || fabs(polarMotion->s - s) > DBL_EPSILON) {
-    //        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-    //                "psEOC_GetPolarMotion returned incorrect values.\n");
-    if (VERBOSE) {
-        printf("  <>PolarMotion output (IERSB)   = x,y,s = %.13g,  %.13g, %.13g\n",
-               polarMotion->x, polarMotion->y, polarMotion->s);
-    }
-    //        printf("  <>PolarMotion expected (IERSB) = x,y,s = %.13g, %.13g, %.13g\n",
-    //               x, y, s);
-    //        return 3;
-    //    }
-    psEarthPole *nutationCorr = psEOC_NutationCorr(in);
-    if (nutationCorr == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false, "Nutation Correction returned NULL.\n");
-        return 6;
-    }
-    polarMotion->x += nutationCorr->x;
-    polarMotion->y += nutationCorr->y;
-    polarMotion->s += nutationCorr->s;
-    psEarthPole *polarTide = psEOC_PolarTideCorr(in);
-    polarMotion->x += polarTide->x;
-    polarMotion->y += polarTide->y;
-    psFree(polarTide);
-    x = -6.43607313124045e-7;
-    y = 2.11351436973568e-6;
-    s = -7.39617581324646e-12;
-    //    if ( fabs(polarMotion->x - x) > DBL_EPSILON || fabs(polarMotion->y - y) > DBL_EPSILON
-    //            || fabs(polarMotion->s - s) > DBL_EPSILON) {
-    //        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-    //                "   psEOC_GetPolarMotion returned incorrect values.\n");
-    if (VERBOSE) {
-        printf("\n  PolarMotion + NutationCorr out = x,y,s = %.13g, %.13g, %.13g\n",
-               polarMotion->x, polarMotion->y, polarMotion->s);
-        printf("  Expected output                = x,y,s = %.13g,  %.13g, %.13g\n", x, y, s);
-        printf("                     Difference  = x,y,s = %.13g, %.13g,  %.13g\n",
-               polarMotion->x - x, polarMotion->y - y, polarMotion->s - s);
-    }
-    //    }
-
-    if (!p_psEOCFinalize() ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "EOC failed finalization!\n");
-        return 12;
-    }
-
-    psFree(nutationCorr);
-    psFree(in);
-    psFree(polarMotion);
-    return 0;
-}
-
-psS32 testEOCPolarTide(void)
-{
-    psTime *in = psTimeAlloc(PS_TIME_UTC);
-    in->sec = timesec;
-    in->nsec = 0;
-    in->leapsecond = false;
-    psTime *empty = NULL;
-    psEarthPole *eop = NULL;
-
-    //Return NULL for NULL input time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    eop = psEOC_PolarTideCorr(empty);
-    if (eop != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_PolarTideCorr failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-
-    eop = psEOC_PolarTideCorr(in);
-    if (eop == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_PolarTideCorr returned NULL for valid input time.\n");
-        return 2;
-    } else {
-        if (VERBOSE) {
-            printf("\nPolarTideCorr output = x,y,s = %.13g, %.13g, %.13g\n",
-                   eop->x, eop->y, eop->s);
-        }
-    }
-
-    psFree(in);
-    psFree(eop);
-
-    return 0;
-}
-
-psS32 testEOCNutation(void)
-{
-    psTime *in = psTimeAlloc(PS_TIME_UTC);
-    in->sec = timesec;
-    in->nsec = 0;
-    in->leapsecond = false;
-    psTime *empty = NULL;
-    psEarthPole *nute = NULL;
-
-    //Return NULL for NULL input time.
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    nute = psEOC_NutationCorr(empty);
-    if (nute != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psEOC_NutationCorr failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-    //Return NULL for UT1 time input
-    /*    psTime *UT1time = psTimeAlloc(PS_TIME_UT1);
-        nute = psEOC_NutationCorr(UT1time);
-        if (nute != NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "psEOC_NutationCorr failed to return NULL for UT1 input time.\n");
-            return 2;
-        }
-        psFree(UT1time);
-    */
-    //Check return values from valid nutation time input
-    nute = psEOC_NutationCorr(in);
-    if ( nute == NULL ) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psEOC_NutationCorr returned NULL for valid input.\n");
-        return 3;
-    } else {
-        if (VERBOSE) {
-            printf("Nutation Correction output = x,y,s = %.13g, %.13g, %.13g\n\n",
-                   nute->x, nute->y, nute->s);
-        }
-    }
-    psFree(nute);
-    psFree(in);
-
-    if (!p_psEOCFinalize() ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "EOC failed finalization!\n");
-        return 12;
-    }
-
-    return 0;
-}
-
-psS32 testSphereRot_TEOtoCEO(void)
-{
-    psSphereRot *rot = NULL;
-    psTime *empty = NULL;
-    psTime *time = psTimeAlloc(PS_TIME_UT1);
-    time->sec = timesec-1;
-    time->nsec = 657017200;
-    time->leapsecond = false;
-
-    //return NULL for NULL input time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    rot = psSphereRot_TEOtoCEO(empty, NULL);
-    if (rot != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_TEOtoCEO failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-
-    psEarthPole *polarTideCorr = psEOC_PolarTideCorr(time);
-    psSphereRot *teoceo = psSphereRot_TEOtoCEO(time, polarTideCorr);
-    //Make sure values match for other psTime type
-    empty = psTimeAlloc(PS_TIME_UTC);
-    empty->sec = timesec;
-    empty->nsec = 0;
-    empty->leapsecond = false;
-
-    rot = psSphereRot_TEOtoCEO(empty, polarTideCorr);
-    if (fabs(rot->q0-teoceo->q0) > 0.00001 || fabs(rot->q1-teoceo->q1) > 0.00001 ||
-            fabs(rot->q2-teoceo->q2) > 0.00001 || fabs(rot->q3-teoceo->q3) > 0.00001) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_TEOtoCEO failed to return matching values for different time types.\n");
-        if (VERBOSE) {
-            printf("\n  Output Rotation1 = q0,q1,q2,q3 = %.13g, %.13g, %.13g, %.13g\n",
-                   teoceo->q0, teoceo->q1, teoceo->q2, teoceo->q3 );
-            printf("\n  Output Rotation2 = q0,q1,q2,q3 = %.13g, %.13g, %.13g, %.13g\n",
-                   rot->q0, rot->q1, rot->q2, rot->q3 );
-        }
-        return 2;
-    }
-    if (VERBOSE) {
-        printf("\n  Output Rotation = q0,q1,q2,q3 = %.13g, %.13g, %.13g, %.13g\n",
-               teoceo->q0, teoceo->q1, teoceo->q2, teoceo->q3 );
-    }
-
-    objSetup();
-    psSphereRot *earthRot = psSphereRotConjugate(NULL, teoceo);
-    psSphere *result = psSphereRotApply(NULL, earthRot, obj);
-    //    psSphere *result = psSphereRotApply(NULL, teoceo, obj);
-    psCube *cube = psSphereToCube(result);
-
-    double x, y, z;
-    x = 0.01698625430807123;
-    y = -0.6616523084626379;
-    z = 0.7496183628158023;
-    if ( fabs(x-cube->x) > FLT_EPSILON  || fabs(y-cube->y) > FLT_EPSILON ||
-            fabs(z-cube->z) > FLT_EPSILON) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_TEOtoCEO returned incorrect values.\n");
-        if (VERBOSE) {
-            printf("\nOutput cube = x,y,z = %.13g, %.13g, %.13g\n",
-                   cube->x, cube->y, cube->z);
-            printf("Expected cube = x,y,z = %.13g, %.13g, %.13g\n", x, y, z);
-            printf("A difference of:   %.13g, %.13g, %.13g\n\n",
-                   (x-cube->x), (y-cube->y), (z-cube->z));
-        }
-        return 3;
-    }
-
-    psFree(polarTideCorr);
-    psFree(rot);
-    psFree(empty);
-    psFree(result);
-    psFree(obj);
-    psFree(earthRot);
-    psFree(cube);
-    psFree(time);
-    psFree(teoceo);
-    return 0;
-}
-
-psS32 testSphereRot_CEOtoGCRS(void)
-{
-    psEarthPole *in = psEarthPoleAlloc();
-    psEarthPole *empty = NULL;
-    psSphereRot *rot = NULL;
-    in->x = 2.857175590089105e-4;
-    in->y = 2.3968739377734732e-5;
-    in->s = -1.3970066457904322e-8;
-
-    double q0,q1,q2,q3;
-    q0 = -1.1984522406756289e-5;
-    q1 = 1.4285893358610674e-4;
-    q2 = 1.2191193518914336e-10;
-    q3 = -0.9999999897238481;
-
-    //Return NULL for NULL input earthpole
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    rot = psSphereRot_CEOtoGCRS(empty);
-    if (rot != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_CEOtoGCRS failed to return NULL for NULL input psEarthPole.\n");
-        return 1;
-    }
-
-    rot = psSphereRot_CEOtoGCRS(in);
-    if (rot == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psSphereRot_CEOtoGCRS returned NULL for valid psEarthPole input.\n");
-        return 2;
-    }
-
-    if (VERBOSE) {
-        printf("\n  Output sphere rotation   = %.13g, %.13g, %.13g, %.13g\n",
-               rot->q0, rot->q1, rot->q2, rot->q3);
-        printf("  Expected sphere rotation = %.13g, %.13g, %.13g, %.13g\n", q0,q1,q2,q3);
-        printf("  difference:                 %.13g, %.13g, %.13g \n",
-               (rot->q0-q0), (rot->q1-q1), (rot->q2-q2) );
-    }
-    if (fabs(rot->q0-q0) > FLT_EPSILON || fabs(rot->q1-q1) > FLT_EPSILON ||
-            fabs(rot->q2-q2) > FLT_EPSILON || fabs(rot->q3+q3) > FLT_EPSILON) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_CEOtoGCRS failed to return expected values.\n");
-        return 3;
-    }
-    psCube *tempCube = psCubeAlloc();
-    tempCube->x = -0.35963388069046304;
-    tempCube->y = 0.5555192509816625;
-    tempCube->z = 0.7497078321908413;
-    obj = psCubeToSphere(tempCube);
-    psFree(tempCube);
-    psSphereRot *precessionNutation = psSphereRotConjugate(NULL, rot);
-    psSphere *result = psSphereRotApply(NULL, precessionNutation, obj);
-    psCube *cube = psSphereToCube(result);
-    double x, y, z;
-    x = -0.3598480726985338;
-    y = 0.5555012823608123;
-    z = 0.7496183628158023;
-    if (VERBOSE) {
-        printf("\n  Output cube = x,y,z = %.13g,  %.13g,    %.13g\n", cube->x, cube->y, cube->z);
-        printf("Expected cube = x,y,z = %.13g,  %.13g,   %.13g\n", x, y, z);
-        printf("  A difference of:    %.13g, %.13g, %.13g\n\n",
-               (x-cube->x), (y-cube->y), (z-cube->z));
-    }
-    psCube *expect = psCubeAlloc();
-    expect->x = x;
-    expect->y = y;
-    expect->z = z;
-    psSphere *expected = psCubeToSphere(expect);
-    double d = greatCircle(result, expected);
-    if (VERBOSE) {
-        printf("   The great circle angular distance between expected & result = %.13g\n", d);
-    }
-
-    psFree(expect);
-    psFree(expected);
-    psFree(obj);
-    psFree(precessionNutation);
-    psFree(result);
-    psFree(cube);
-    psFree(rot);
-    psFree(in);
-
-    return 0;
-}
-
-psS32 testSphereRot_ITRStoTEO(void)
-{
-    psEarthPole *in = psEarthPoleAlloc();
-    psEarthPole *empty = NULL;
-    psSphereRot *rot = NULL;
-    in->x = -0.13275353774074533;
-    in->y = 0.4359436319739848;
-    in->s = -4.2376965863576153e-10;
-    in->x = SEC_TO_RAD(in->x);
-    in->y = SEC_TO_RAD(in->y);
-    in->s = SEC_TO_RAD(in->s);
-
-    //Return NULL for NULL input earthpole
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    rot = psSphereRot_ITRStoTEO(empty);
-    if (rot != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereRot_ITRStoTEO failed to return NULL for NULL input psEarthPole.\n");
-        return 1;
-    }
-
-    rot = psSphereRot_ITRStoTEO(in);
-    if (rot == NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psSphereRot_ITRStoTEO return NULL for valid psEarthPole input.\n");
-        return 2;
-    }
-
-    double q0,q1,q2,q3;
-    q0 = -1.0567571848664005e-6;
-    q1 = 3.218036562931509e-7;
-    q2 = -3.3580195807204483e-12;
-    q3 = -0.9999999999993899;
-    if (fabs(rot->q0-q0) > FLT_EPSILON || fabs(rot->q1-q1) > FLT_EPSILON ||
-            fabs(rot->q2-q2) > FLT_EPSILON
-            //            || fabs(rot->q3-q3) > DBL_EPSILON
-       ) {
-        if (VERBOSE) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "psSphereRot_ITRStoTEO failed to return expected values.\n");
-            printf("\n  Output sphere rotation   = %.13g, %.13g, %.13g, %.13g\n",
-                   rot->q0, rot->q1, rot->q2, rot->q3);
-            printf("  Expected sphere rotation = %.13g, %.13g, %.13g, %.13g\n", q0,q1,q2,q3);
-            printf("  a difference:   %.13g, %.13g, %.13g, %.13g \n", (rot->q0-q0), (rot->q1-q1),
-                   (rot->q2-q2), (rot->q3-q3) );
-        }
-        //        printf("Error #3\n");
-        //        return 3;
-    }
-    if (VERBOSE) {
-        printf("\n  Output sphere rotation   = %.13g, %.13g, %.13g, %.13g\n",
-               rot->q0, rot->q1, rot->q2, rot->q3);
-        printf("  Expected sphere rotation = %.13g, %.13g, %.13g, %.13g\n", q0,q1,q2,q3);
-    }
-
-    psCube *temp = psCubeAlloc();
-    //    temp->x = -0.3596195125758298;
-    //    temp->y = 0.5555613903455866;
-    //    temp->z = 0.7496834983724809;
-    temp->x = 0.01698625430807123;
-    temp->y = -0.6616523084626379;
-    temp->z = 0.7496183628158023;
-
-    obj = psCubeToSphere(temp);
-    psSphere *test = NULL;
-    psFree(temp);
-    psSphereRot *newRot = psSphereRotConjugate(NULL, rot);
-    test = psSphereRotApply(NULL, newRot, obj);
-    temp = psSphereToCube(test);
-    double x, y, z;
-    x = 0.01698577185310146;
-    y = -0.6616538927902393;
-    z = 0.7496169753347885;
-    if (VERBOSE) {
-        printf("\n  Cube -test- has x,y,z =     %.13g, %.13g, %.13g \n",
-               temp->x, temp->y, temp->z);
-        printf("\n  Cube -expected- has x,y,z = %.13g,  %.13g, %.13g \n", x, y, z );
-    }
-    temp->x = x;
-    temp->y = y;
-    temp->z = z;
-    psSphere *sphere = psCubeToSphere(temp);
-    double d = greatCircle(sphere, test);
-    if (VERBOSE) {
-        printf("Great circle difference of:  %.13g \n", d);
-    }
-
-    psFree(sphere);
-    psFree(newRot);
-    psFree(obj);
-    psFree(temp);
-    psFree(test);
-    psFree(rot);
-    psFree(in);
-
-    return 0;
-}
-
-#define SPHERE_PRECESS_TP1_R            0.0               //    0.0       degrees
-#define SPHERE_PRECESS_TP1_D            0.0               //    0.0       degrees
-#define SPHERE_PRECESS_TP1_EXPECT_R     6.238453          //  357.437     degrees
-#define SPHERE_PRECESS_TP1_EXPECT_D    -0.019426          //   -1.113     degrees
-#define SPHERE_PRECESS_TP2_R            0.0               //    0.0       degrees
-#define SPHERE_PRECESS_TP2_D            1.570796          //   90.0       degrees
-#define SPHERE_PRECESS_TP2_EXPECT_R     6.260828          //  358.719     degrees
-#define SPHERE_PRECESS_TP2_EXPECT_D     1.551353          //   88.886     degrees
-#define SPHERE_PRECESS_TP3_R            3.141593          //  180.0       degrees
-#define SPHERE_PRECESS_TP3_D            0.523599          //   30.0       degrees
-#define SPHERE_PRECESS_TP3_EXPECT_R     3.096616          //  177.423     degrees
-#define SPHERE_PRECESS_TP3_EXPECT_D     0.543024          //   31.113     degrees
-#define ERROR_TOL   0.0001
-#define MJD_1900  15021.0        // Modified Julian Day 1/1/1900 00:00:00
-#define MJD_2100  88069.0        // Modified Julian Day 1/1/2100 00:00:00
-
-psS32 testSphereRotPrecess( void )
-{
-
-    psSphere*     inputCoord  = psSphereAlloc();
-    psSphere*     outputCoord = NULL;
-    //    psTime*       fromTime    = psTimeFromMJD(MJD_1900);
-    //    psTime*       toTime      = psTimeFromMJD(MJD_2100);
-    psTime*       fromTime    = psTimeFromMJD(MJD_2100);
-    psTime*       toTime      = psTimeFromMJD(MJD_1900);
-    psSphereRot *rot = NULL;
-    // Set input coordinate
-    inputCoord->r = SPHERE_PRECESS_TP1_R;
-    inputCoord->d = SPHERE_PRECESS_TP1_D;
-    inputCoord->rErr = 0.0;
-    inputCoord->dErr = 0.0;
-
-    // Calculate precess
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_ROUGH);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.0001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    //    outputCoord = psSpherePrecess(inputCoord, fromTime, toTime, PS_PRECESS_ROUGH);
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 1;
-    }
-    // Verify return with expected values
-    if( fabs(outputCoord->r - SPHERE_PRECESS_TP1_EXPECT_R) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess r = %lg not equal to expected = %lg",
-                outputCoord->r,SPHERE_PRECESS_TP1_EXPECT_R);
-        return 2;
-    }
-    if( fabs(outputCoord->d - SPHERE_PRECESS_TP1_EXPECT_D) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess d = %lg not equal to expected = %lg",
-                outputCoord->d,SPHERE_PRECESS_TP1_EXPECT_D);
-        return 3;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    // Set input coordinate
-    inputCoord->r = SPHERE_PRECESS_TP2_R;
-    inputCoord->d = SPHERE_PRECESS_TP2_D;
-    inputCoord->rErr = 0.0;
-    inputCoord->dErr = 0.0;
-
-    // Calculate precess
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_ROUGH);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.0001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    //    outputCoord = psSpherePrecess(inputCoord, fromTime, toTime, PS_PRECESS_ROUGH);
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 4;
-    }
-    // Verify return with expected values
-    if( fabs(outputCoord->r - SPHERE_PRECESS_TP2_EXPECT_R) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess r = %lg not equal to expected = %lg",
-                outputCoord->r,SPHERE_PRECESS_TP2_EXPECT_R);
-        return 5;
-    }
-    if( fabs(outputCoord->d - SPHERE_PRECESS_TP2_EXPECT_D) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess d = %lg not equal to expected = %lg",
-                outputCoord->d,SPHERE_PRECESS_TP2_EXPECT_D);
-        return 6;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    // Set input coordinate
-    inputCoord->r = SPHERE_PRECESS_TP3_R;
-    inputCoord->d = SPHERE_PRECESS_TP3_D;
-    inputCoord->rErr = 0.0;
-    inputCoord->dErr = 0.0;
-
-    // Calculate precess
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_ROUGH);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.0001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    //    outputCoord = psSpherePrecess(inputCoord, fromTime, toTime, PS_PRECESS_ROUGH);
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 7;
-    }
-    // Verify return with expected values
-    if( fabs(outputCoord->r - SPHERE_PRECESS_TP3_EXPECT_R) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess r = %lg not equal to expected = %lg",
-                outputCoord->r,SPHERE_PRECESS_TP3_EXPECT_R);
-        return 8;
-    }
-    if( fabs(outputCoord->d - SPHERE_PRECESS_TP3_EXPECT_D) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Precess d = %lg not equal to expected = %lg",
-                outputCoord->d,SPHERE_PRECESS_TP3_EXPECT_D);
-        return 9;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    //Test other modes (IAU2000A, COMPLETE_[A,B])
-    // Set input coordinate
-    inputCoord->r = SPHERE_PRECESS_TP1_R;
-    inputCoord->d = SPHERE_PRECESS_TP1_D;
-    inputCoord->rErr = 0.0;
-    inputCoord->dErr = 0.0;
-    // Calculate precess
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_COMPLETE_A);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.000001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 10;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_COMPLETE_B);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.000001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 11;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    rot = psSpherePrecess(fromTime, toTime, PS_PRECESS_IAU2000A);
-    outputCoord = psSphereRotApply(NULL, rot, inputCoord);
-    if (outputCoord->r < -0.000001) {
-        outputCoord->r += 2.0 * M_PI;
-    }
-    // Verify return is not NULL
-    if(outputCoord == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL not expected");
-        return 12;
-    }
-    psFree(outputCoord);
-    psFree(rot);
-
-    // Invoke precess with invalid parameter
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message");
-    rot = psSpherePrecess(fromTime, toTime, 10);
-    if(rot != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with invalid input");
-        return 14;
-    }
-    // Return NULL for NULL input times
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message");
-    rot = psSpherePrecess(NULL, NULL, PS_PRECESS_ROUGH);
-    if(rot != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL with invalid input");
-        return 15;
-    }
-
-    if (!p_psEOCFinalize() ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "EOC failed finalization!\n");
-        return 12;
-    }
-    // Free objects
-    psFree(fromTime);
-    psFree(toTime);
-    psFree(inputCoord);
-
-    return 0;
-}
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psSphereOps.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psSphereOps.c	(revision 30117)
+++ 	(revision )
@@ -1,390 +1,0 @@
-/** @file  tst_psSphereOps.c
-*
-*  @brief The code will perform sphere rotations and transformations.
-*
-*  @author d-Rob, MHPCC
-*
-*  @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-02-02 23:19:58 $
-*
-*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
-*/
-
-#include "psTest.h"
-#include "pslib_strict.h"
-
-static psS32 testSphereRotAlloc(void);
-static psS32 testSphereRotQuat(void);
-static psS32 testSphereRotApply1(void);
-static psS32 testSphereRotApplyCelestial(void);
-static psS32 testSphereOffset(void);
-
-testDescription tests[] = {
-                              {testSphereRotAlloc, 819, "psSphereRotAlloc()", 0, false},
-                              {testSphereRotQuat, 820, "psSphereRotQuat()", 0, false},
-                              {testSphereRotApply1, 821, "psSphereRotApply()", 0, false},
-                              {testSphereRotApplyCelestial, 822, "psSphereRotApplyCel()", 0, false},
-                              {testSphereOffset, 825, "testSphereOffset()", 0, false},
-                              {NULL}
-                          };
-
-psS32 main( psS32 argc, char* argv[] )
-{
-    psLogSetLevel( PS_LOG_INFO );
-    psLogSetFormat("HLNM");
-
-    return ( ! runTestSuite( stderr, "psSphereOps", tests, argc, argv ) );
-}
-
-#define DEG_INC   30.0
-
-#define MJD_1900  15021.0        // Modified Julian Day 1/1/1900 00:00:00
-#define MJD_2000  51544.0        // Modified Julian Day 1/1/2000 00:00:00
-#define MJD_2100  88069.0        // Modified Julian Day 1/1/2100 00:00:00
-
-#define ERROR_TOL   0.0001
-
-#define ALPHA_P 4*M_PI/3
-#define DELTA_P M_PI/4
-#define PHI_P M_PI/3
-
-psS32 testSphereRotAlloc( void )
-{
-    // Allocate data structure
-    psSphereRot* myST = psSphereRotAlloc(ALPHA_P, DELTA_P, PHI_P);
-
-    // Verify null not returned
-    if(myST == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL with valid parameters");
-        return 1;
-    }
-
-    double a0 = (ALPHA_P - PHI_P)/2.0;
-    double a1 = (ALPHA_P - PHI_P)/2.0;
-    double a2 = (ALPHA_P + PHI_P)/2.0;
-    double a3 = (ALPHA_P + PHI_P)/2.0;
-    //From Mathworld, this is another way to calculate the quaternions of a rotation
-    double q0 = sin(a0)*sin(DELTA_P/2);
-    double q1 = cos(a1)*sin(DELTA_P/2);
-    double q2 = sin(a2)*cos(DELTA_P/2);
-    double q3 = cos(a3)*cos(DELTA_P/2);
-    //Check that the quaternion components all match
-    if (DBL_EPSILON < fabs(q0 - myST->q0)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q0 is %lf, should be %lf\n", myST->q0, q0);
-        return 2;
-    }
-    if (DBL_EPSILON < fabs(q1 - myST->q1)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q1 is %f, should be %f\n", myST->q1, q1);
-        return 3;
-    }
-    if (DBL_EPSILON < fabs(q2 - myST->q2)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q2 is %f, should be %f\n", myST->q2, q2);
-        return 4;
-    }
-    if (DBL_EPSILON < fabs(q3 - myST->q3)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q0 is %f, should be %f\n", myST->q3, q3);
-        return 5;
-    }
-
-    // Free data structure
-    psFree(myST);
-
-    return 0;
-}
-
-psS32 testSphereRotQuat(void)
-{
-    double a0 = (ALPHA_P - PHI_P)/2.0;
-    double a1 = (ALPHA_P - PHI_P)/2.0;
-    double a2 = (ALPHA_P + PHI_P)/2.0;
-    double a3 = (ALPHA_P + PHI_P)/2.0;
-    //From Mathworld, this is another way to calculate the quaternions of a rotation
-    double q0 = sin(a0)*sin(DELTA_P/2);
-    double q1 = cos(a1)*sin(DELTA_P/2);
-    double q2 = sin(a2)*cos(DELTA_P/2);
-    double q3 = cos(a3)*cos(DELTA_P/2);
-
-    psSphereRot *myST = psSphereRotQuat(q0*2.0, q1*2.0, q2*2.0, q3*2.0);
-    // Verify null not returned
-    if(myST == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL with valid parameters");
-        return 1;
-    }
-    //Check that the quaternion components all match
-    if (FLT_EPSILON < fabs(q0 - myST->q0)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q0 is %lf, should be %lf\n", myST->q0, q0);
-        return 2;
-    }
-    if (FLT_EPSILON < fabs(q1 - myST->q1)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q1 is %f, should be %f\n", myST->q1, q1);
-        return 3;
-    }
-    if (FLT_EPSILON < fabs(q2 - myST->q2)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q2 is %f, should be %f\n", myST->q2, q2);
-        return 4;
-    }
-    if (FLT_EPSILON < fabs(q3 - myST->q3)) {
-        psError(PS_ERR_UNKNOWN,true,"myST->q0 is %f, should be %f\n", myST->q3, q3);
-        return 5;
-    }
-
-    // Free data structure
-    psFree(myST);
-
-    return 0;
-}
-
-// We do a simple identity transformation on a few RA, DEC pairs.
-psS32 testSphereRotApply1( void )
-{
-    psSphere *in = psSphereAlloc();
-    psSphere *out = psSphereAlloc();
-    psSphere *temp = NULL;
-    psSphere *rc = NULL;
-    psSphere *temp2 = psSphereAlloc();
-    psSphereRot *myST = psSphereRotAlloc(ALPHA_P, DELTA_P, PHI_P);
-    psSphereRot *yourST =  psSphereRotInvert(ALPHA_P, DELTA_P, PHI_P);
-
-    for (float r=0.0;r<180.0;r+=DEG_INC) {
-        for (float d=0.0;d<90.0;d+=DEG_INC) {
-            in->r = DEG_TO_RAD(r);
-            in->d = DEG_TO_RAD(d);
-            in->rErr = 0.0;
-            in->dErr = 0.0;
-            //Here we apply the sphere rotation, then the inverse
-            temp2 = psSphereRotApply(temp2, myST, in);
-            out = psSphereRotApply(out, yourST, temp2);
-            //Check that out matches in
-            if (ERROR_TOL < fabs(out->r - in->r)) {
-                psError(PS_ERR_UNKNOWN,true,"out->r is %f, should be %f\n", out->r, in->r);
-                return 2;
-            }
-            if (ERROR_TOL < fabs(out->d - in->d)) {
-                psError(PS_ERR_UNKNOWN,true,"out->d is %f, should be %f\n", out->d, in->d);
-                return 3;
-            }
-        }
-    }
-    // Verify new sphere object is created if out parameter NULL
-    temp = psSphereRotApply(NULL, myST, in);
-    if ( temp == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Returned NULL when out parameter was null");
-        return 4;
-    }
-    psFree(temp);
-
-    // Verify NULL returned if transform structure null
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    rc = psSphereRotApply(NULL, NULL, in);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psSphereRotApply() did not return NULL.");
-        return 5;
-    }
-
-    // Verify NULL returned when input sphere is NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    rc = psSphereRotApply(NULL, myST, NULL);
-    if (rc != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"psSphereRotApply() did not return NULL");
-        return 6;
-    }
-
-    psFree(myST);
-    psFree(yourST);
-    psFree(temp2);
-    psFree(out);
-    psFree(in);
-
-    return 0;
-}
-
-#define ERROR_PERCENT 0.01
-
-psS32 testSphereRotApplyCelestial( void)
-{
-    //Test cases below were provided in ADD.
-    int numTestPoints = 3;
-    // ICRS coordinates
-    double alpha[] = {  0.0,        0.0,     180.0     };
-    double delta[] = {  0.0,       90.0,      30.0     };
-    //Ecliptic coordinates
-    double lambda[] ={  0.0,       90.0,     167.072470};
-    double beta[] =  {  0.0,       66.560719, 27.308813};
-    // Galactic coordinates
-    double l[] =     { 96.337272, 122.93192, 195.639488};
-    double b[] =     {-60.188553,  27.12825,  78.353806};
-    double t[] =     {  MJD_2000,  MJD_2000,   MJD_2100};
-    double TOLERANCE = 0.001;
-
-    for (int x = 0; x < numTestPoints; x++) {
-        //Setup the appropriate rotations
-        psTime* time = psTimeFromMJD(t[x]);
-        psSphereRot* toEcliptic = psSphereRotICRSToEcliptic(time);
-        psSphereRot* fromEcliptic = psSphereRotEclipticToICRS(time);
-        psSphereRot* toGalactic = psSphereRotICRSToGalactic();
-        psSphereRot* fromGalactic = psSphereRotGalacticToICRS();
-        psFree(time);
-
-        // set the ICRS coordinate
-        psSphere* icrs = psSphereAlloc();
-        icrs->r = DEG_TO_RAD(alpha[x]);
-        icrs->d = DEG_TO_RAD(delta[x]);
-
-        // apply/unapply Ecliptic
-        psSphere* ecliptic = psSphereRotApply(NULL, toEcliptic, icrs);
-        psSphere* icrsFromEcliptic = psSphereRotApply(NULL, fromEcliptic, ecliptic);
-
-        // check ecliptic transforms for correctness
-        if (fabs(RAD_TO_DEG(ecliptic->r) - lambda[x]) > TOLERANCE ||
-                fabs(RAD_TO_DEG(ecliptic->d) - beta[x]) > TOLERANCE) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "Ecliptic tranformation incorrect.  Result is (%g,%g), expected (%g,%g)",
-                    RAD_TO_DEG(ecliptic->r),RAD_TO_DEG(ecliptic->d),
-                    lambda[x], beta[x]);
-            return 1;
-        }
-        //The second condition here (d - 90) is used b/c 90 is a pole.
-        if ( (fabs(RAD_TO_DEG(icrsFromEcliptic->r) - alpha[x]) > TOLERANCE &&
-                fabs(RAD_TO_DEG(icrsFromEcliptic->d) - 90.0) > TOLERANCE ) ||
-                fabs(RAD_TO_DEG(icrsFromEcliptic->d) - delta[x]) > TOLERANCE) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "ICRS for Ecliptic tranformation incorrect.  Result is (%g,%g), expected (%g,%g)",
-                    RAD_TO_DEG(icrsFromEcliptic->r),RAD_TO_DEG(icrsFromEcliptic->d),
-                    alpha[x], delta[x]);
-            return 2;
-        }
-        psFree(ecliptic);
-        psFree(icrsFromEcliptic);
-
-        //Setup galactic transformations
-        psSphere* galactic = psSphereRotApply(NULL, toGalactic, icrs);
-        psSphere* icrsFromGalactic = psSphereRotApply(NULL, fromGalactic, galactic);
-
-        // check ecliptic transforms for correctness
-        if (fabs(RAD_TO_DEG(galactic->r) - l[x]) > TOLERANCE ||
-                fabs(RAD_TO_DEG(galactic->d) - b[x]) > TOLERANCE) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "Galactic tranformation incorrect.  Result is (%g,%g), expected (%g,%g)",
-                    RAD_TO_DEG(galactic->r),RAD_TO_DEG(galactic->d),
-                    l[x], b[x]);
-            return 3;
-        }
-        //The second condition here (d - 90) is used b/c 90 is a pole.
-        if ( (fabs(RAD_TO_DEG(icrsFromGalactic->r) - alpha[x]) > TOLERANCE &&
-                fabs(RAD_TO_DEG(icrsFromGalactic->d) - 90.0) > TOLERANCE ) ||
-                fabs(RAD_TO_DEG(icrsFromGalactic->d) - delta[x]) > TOLERANCE) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "ICRS for Galactic tranformation incorrect.  Result is (%g,%g), expected (%g,%g)",
-                    RAD_TO_DEG(icrsFromGalactic->r),RAD_TO_DEG(icrsFromGalactic->d),
-                    alpha[x], delta[x]);
-            return 4;
-        }
-        psFree(galactic);
-        psFree(icrsFromGalactic);
-        psFree(icrs);
-        psFree(toEcliptic);
-        psFree(fromEcliptic);
-        psFree(toGalactic);
-        psFree(fromGalactic);
-    }
-    return 0;
-}
-
-psS32 testSphereOffset(void)
-{
-    psSphere *origin = psSphereAlloc();
-    psSphere *offset = psSphereAlloc();
-    psSphere *dest = psSphereAlloc();
-    psSphere *empty = NULL;
-    psSphere *output = NULL;
-
-    //Test Set for NULL position
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    output = psSphereSetOffset(empty, offset, PS_SPHERICAL, PS_DEGREE);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereSetOffset Failed to return NULL for NULL input.\n");
-        return 1;
-    }
-    //Test Set for NULL offset
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    output = psSphereSetOffset(offset, empty, PS_SPHERICAL, PS_DEGREE);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereSetOffset Failed to return NULL for NULL input.\n");
-        return 2;
-    }
-    //Test Get for NULL position1
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    output = psSphereGetOffset(empty, origin, PS_LINEAR, PS_RADIAN);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereGetOffset Failed to return NULL for NULL input.\n");
-        return 3;
-    }
-    //Test Get for NULL position2
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error");
-    output = psSphereGetOffset(origin, empty, PS_LINEAR, PS_RADIAN);
-    if (output != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereGetOffset Failed to return NULL for NULL input.\n");
-        return 4;
-    }
-
-    //Test Set using Spherical mode, Degree units
-    origin->r = 0.0;
-    origin->d = 0.0;
-    offset->r = 45.0;
-    offset->d = 30.0;
-    output = psSphereSetOffset(origin, offset, PS_SPHERICAL, PS_DEGREE);
-    if ( fabs(output->r - M_PI/4.0) > 0.0001 ||
-            fabs(output->d - M_PI/6.0) > 0.0001 ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereSetOffset failed to return correct spherical offset values.\n");
-        return 5;
-    }
-    psFree(output);
-
-    //Test Set and Get using Linear mode, Radian units
-    origin->r = 0.0;
-    origin->d = 0.0;
-    offset->r = 1.0;
-    offset->d = 1.0;
-    output = psSphereSetOffset(origin, offset, PS_LINEAR, PS_RADIAN);
-
-    empty = psSphereGetOffset(origin, output, PS_LINEAR, PS_RADIAN);
-    if ( fabs(offset->r - empty->r) > 0.0001 || fabs(offset->d - empty->d) > 0.0001 ) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereGetOffset failed to return correct linear offset values.\n");
-        return 7;
-    }
-    psFree(output);
-    psFree(empty);
-
-    //Test Set using Linear mode, Arcmin units
-    origin->r = 0.0;
-    origin->d = 0.0;
-    offset->r = RAD_TO_MIN(M_PI / 4.0);     //45 deg
-    offset->d = RAD_TO_MIN(M_PI / 6.0);     //30 deg
-    output = psSphereSetOffset(origin, offset, PS_SPHERICAL, PS_ARCMIN);
-    //Test Get using Spherical mode, Arcsec units
-    empty = psSphereGetOffset(origin, output, PS_SPHERICAL, PS_ARCSEC);
-    empty->r = SEC_TO_RAD(empty->r);
-    empty->d = SEC_TO_RAD(empty->d);
-    if (fabs(empty->r - (M_PI / 4.0)) > 0.001 || fabs(empty->d - (M_PI / 6.0)) > 0.001) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psSphereGetOffset failed to return correct offset unit values.\n");
-        printf("\n SphereGetOffset should be %lf, %lf and is %lf, %lf\n", output->r, output->d,
-               empty->r, empty->d);
-        return 8;
-    }
-    psFree(output);
-
-    psFree(origin);
-    psFree(dest);
-    psFree(offset);
-    psFree(empty);
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psTime_01.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psTime_01.c	(revision 30117)
+++ 	(revision )
@@ -1,1163 +1,0 @@
-/** @file  tst_psTime_01.c
- *
- *  @brief Test driver for psTime functions
- *
- *  This test driver contains the following tests for psTime:
- *     1) Allocate psTime structure
- *     2) Get current time
- *     3) Get UT1 UTC delta
- *     4) Convert psTime to MJD
- *     5) Convert psTime to JD
- *     6) Convert psTime to ISO
- *     7) Convert psTime to timeval
- *     8) Create psTime from MJD
- *     9) Create psTime from JD
- *    10) Create psTime from ISO
- *    11) Create psTime from timeval
- *    12) Create psTime from TM
- *    13) Convert time between different types
- *
- *     O) Convert psTime time to LMST
- *
- *  @author  Ross Harman, MHPCC
- *  @author  Eric Van Alst, MHPCC
- *
- *  @version $Revision: 1.7 $  $Name: not supported by cvs2svn $
- *  @date  $Date: 2006-07-21 00:08:15 $
- *
- *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
- *
- */
-
-#include "pslib_strict.h"
-#include "psTest.h"
-#include <string.h>
-
-#define ERROR_TOL    0.0001
-
-static psS32 testTimeAlloc(void);
-static psS32 testTimeGetNow(void);
-static psS32 testTimeGetUT1Delta(void);
-static psS32 testTimeToMJD(void);
-static psS32 testTimeToJD(void);
-static psS32 testTimeToISO(void);
-static psS32 testTimeToTimeval(void);
-static psS32 testTimeFromMJD(void);
-static psS32 testTimeFromJD(void);
-static psS32 testTimeFromISO(void);
-static psS32 testTimeFromTimeval(void);
-static psS32 testTimeFromTM(void);
-static psS32 testTimeConvert(void);
-
-testDescription tests[] = {
-                              {testTimeAlloc,1,"psTimeAlloc",0,false},
-                              {testTimeGetNow,2,"psTimeGetNow",0,false},
-                              {testTimeGetUT1Delta,3,"psTimeGetUT1Delta",0,false},
-                              {testTimeToMJD,4,"psTimeToMJD",0,false},
-                              {testTimeToJD,5,"psTimeToJD",0,false},
-                              {testTimeToISO,6,"psTimeToISO",0,false},
-                              {testTimeToTimeval,7,"psTimeToTimeval",0,false},
-                              {testTimeFromMJD,8,"psTimeFromMJD",0,false},
-                              {testTimeFromJD,9,"psTimeFromJD",0,false},
-                              {testTimeFromISO,10,"psTimeFromISO",0,false},
-                              {testTimeFromTimeval,11,"psTimeFromTimeval",0,false},
-                              {testTimeFromTM,12,"p_psTimeFromTM",0,false},
-                              {testTimeConvert,666,"psTimeConvert",0,false},
-                              {NULL}
-                          };
-
-// Test Time 1 : July 21, 2004  18:22:24.3
-//               MJD = 53207.765559
-//               JD = 2453208.265559
-// UTC Test Time 1
-const psS64 testTime1SecondsUTC     = 1090434144;
-const psU32 testTime1NanosecondsUTC = 272044000;
-// TAI Test Time 1
-const psS64 testTime1SecondsTAI     = 1090434176;
-const psU32 testTime1NanosecondsTAI = 272044000;
-const psF64 testTime1MJDTAI         = 53207.76592937;
-const psF64 testTime1JDTAI          = 2453208.26592937;
-
-// TT Test Time 1
-const psS64 testTime1SecondsTT      = 1090434208;
-const psU32 testTime1NanosecondsTT  = 456044000;
-// Expected UT1-UTC IERS A & B
-const psF64 testTime1UT1DeltaBullA  = -0.457233186;
-const psF64 testTime1UT1DeltaBullB  = -0.457227;
-// UT1 Test Time 1
-const psS64 testTime1SecondsUT1     = 1090434143;
-//const psU32 testTime1NanosecondsUT1 = 814810814;
-const psU32 testTime1NanosecondsUT1 = 814810861;
-// Expected MJD & JD
-const psF64 testTime1MJD            = 53207.765559;
-const psF64 testTime1JD             = 2453208.265559;
-// Expected ISO string
-const char* testTime1Str     = "2004-07-21T18:22:24.2Z";
-const char* testTime1StrLeap = "2004-07-21T18:22:60.2Z";
-// Expected timeval values
-const psS32 testTime1TimevalSec = 1090434144;
-const psS32 testTime1TimevalUsec = 272044;
-
-// Test Time 2 : Jan. 1, 1973 00:00:00.0000
-//               MJD = 41683.0000
-//               JD = 2441683.5000
-const psS64 testTime2SecondsUTC     = 94694400;
-const psU32 testTime2NanosecondsUTC = 0;
-
-// Expected UT1-UTC IERS A & B
-const psF64 testTime2UT1DeltaBullA  = 0.000000;
-const psF64 testTime2UT1DeltaBullB  = 0.000000;
-
-// Test Time 3 : Sept. 21, 2006 00:00:00.0000
-//               MJD = 53999
-//               JD = 2453999.5
-const psS64 testTime3SecondsUTC     = 1158796800;
-const psU32 testTime3NanosecondsUTC = 0;
-// Expected UT1-UTC IERS A & B
-const psF64 testTime3UT1DeltaBullA  = -0.63574;
-const psF64 testTime3UT1DeltaBullB  = -0.63574;
-
-// Test Time 4 : Jan. 1, 1969 00:00:00.0000
-//               MJD = 40222
-//               JD = 2440222.5
-const psS64 testTime4SecondsUTC     = -31536000;
-const psU32 testTime4NanosecondsUTC = 0;
-// Expected MJD and JD
-const psF64 testTime4MJD            = 40222.0;
-const psF64 testTime4JD             = 2440222.5;
-
-// Test Time 5 : Dec 31, 0001 BC 23:59:59
-//               MJD = -1397755
-//               JD = 1002245.4999
-const psS64 testTime5SecondsUTC     = -62125920001;
-const psU32 testTime5NanosecondsUTC  = 0;
-
-// Test Time 6 : Jan. 1, 10000 AD 00:00:00
-const psS64 testTime6SecondsUTC      = 253202544001;
-const psU32 testTime6NanosecondsUTC  = 0;
-
-// Test Time 7 : Jan. 1, 2004 00:00:00,0
-const psS64 testTime7Seconds         = 1072915200;
-const psU32 testTime7Nanoseconds     = 0;
-const psS32 testTime7TmYear          = 104;
-const psS32 testTime7TmMon           = 0;
-const psS32 testTime7TmDay           = 1;
-const psS32 testTime7TmHour          = 0;
-const psS32 testTime7TmMin           = 0;
-const psS32 testTime7TmSec           = 0;
-
-// Test Time 8 : Dec. 31, 2003 00:00:00,0
-const psS64 testTime8Seconds         = 1072828800;
-const psU32 testTime8Nanoseconds     = 0;
-const psS32 testTime8TmYear          = 103;
-const psS32 testTime8TmMon           = 11;
-const psS32 testTime8TmDay           = 31;
-const psS32 testTime8TmHour          = 0;
-const psS32 testTime8TmMin           = 0;
-const psS32 testTime8TmSec           = 0;
-
-psS32 main(psS32 argc, char* argv[])
-{
-    psLogSetLevel(PS_LOG_INFO);
-
-    // Initialize library internal structures
-    psLibInit("pslib.config");
-
-    if( !runTestSuite(stderr,"psTime",tests,argc,argv)) {
-        return 1;
-    }
-
-    // Cleanup library
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeAlloc(void)
-{
-    psTime*  time = NULL;
-
-    // Allocate new psTime with valid time type
-    time = psTimeAlloc(PS_TIME_TAI);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Return NULL when psTime object ptr expected");
-        return 1;
-    }
-    // Verify members set properly
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Member type = %d not as expected %d",time->type,PS_TIME_TAI);
-        return 2;
-    }
-    if((time->sec != 0) && (time->nsec != 0) && (time->leapsecond != false)) {
-        psError(PS_ERR_UNKNOWN,true,"Members not set appropriately");
-        return 3;
-    }
-    psFree(time);
-
-    // Allocate new psTime with invalid time type
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    time = psTimeAlloc(-100);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time type");
-        return 4;
-    }
-
-    return 0;
-}
-psS32 testTimeGetNow(void)
-{
-    psTime*  timeNow = NULL;
-
-    // Get current time and verify return is psTime structure
-    timeNow = psTimeGetNow(PS_TIME_TAI);
-    if(timeNow == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return valid psTime struct");
-        return 1;
-    }
-    if(timeNow->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Time type %d not as expected %d",
-                timeNow->type, PS_TIME_TAI);
-        return 2;
-    }
-    psFree(timeNow);
-
-    // Attempt to get time with invalid type
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time type");
-    timeNow = psTimeGetNow(-100);
-    if(timeNow != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time type");
-        return 3;
-    }
-
-    return 0;
-}
-
-psS32 testTimeGetUT1Delta(void)
-{
-    psTime*    time      = NULL;
-    psF64      ut1Delta  = 0.0;
-
-    // Attempt to convert NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_B);
-    if( !isnan(ut1Delta)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NAN for NULL psTime");
-        return 1;
-    }
-
-    // Attempt to convert invalid time
-    time = psTimeAlloc(PS_TIME_TAI);
-    time->sec = 1;
-    time->nsec = 2e9;
-    time->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_B);
-    if( !isnan(ut1Delta)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NAN for invalid time");
-        return 2;
-    }
-
-    // Attempt to convert time with invalid bulletin
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid bulletin");
-    time->nsec = 2;
-    ut1Delta = psTimeGetUT1Delta(time,-100);
-    if( !isnan(ut1Delta)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NAN for invalid bulletin");
-        return 3;
-    }
-
-    // Attempt to get delta with valid time and bulletin A
-    time->sec  = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    time->type = PS_TIME_UTC;
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_A);
-    if(fabs(ut1Delta - testTime1UT1DeltaBullA) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 1 bulletin A",
-                ut1Delta,testTime1UT1DeltaBullA);
-        return 4;
-    }
-
-    // Attempt to get delta with valid time and bulletin B
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_B);
-    if(fabs(ut1Delta - testTime1UT1DeltaBullB) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 1 bulletin B",
-                ut1Delta,testTime1UT1DeltaBullB);
-        return 5;
-    }
-
-    // Attempt to get delta with valid time and bulletin A
-    time->sec  = testTime2SecondsUTC;
-    time->nsec = testTime2NanosecondsUTC;
-    time->type = PS_TIME_UTC;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate a warning message predating table");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_A);
-    if(fabs(ut1Delta - testTime2UT1DeltaBullA) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 2 bulletin A",
-                ut1Delta,testTime2UT1DeltaBullA);
-        return 6;
-    }
-
-    // Attempt to get delta with valid time and bulletin B
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate a warning message predating table");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_B);
-    if(fabs(ut1Delta - testTime2UT1DeltaBullB) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 2 bulletin B",
-                ut1Delta,testTime2UT1DeltaBullB);
-        return 7;
-    }
-
-    // Attempt to get delta with valid time and bulletin A
-    time->sec  = testTime3SecondsUTC;
-    time->nsec = testTime3NanosecondsUTC;
-    time->type = PS_TIME_UTC;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate a warning message postdating table");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_A);
-    if(fabs(ut1Delta - testTime3UT1DeltaBullA) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 3 bulletin A",
-                ut1Delta,testTime3UT1DeltaBullA);
-        return 8;
-    }
-
-    // Attempt to get delta with valid time and bulletin B
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate a warning message postdating table");
-    ut1Delta = psTimeGetUT1Delta(time,PS_IERS_B);
-    if(fabs(ut1Delta - testTime3UT1DeltaBullB) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 Delta %lf not as expected %lf test time 3 bulletin B",
-                ut1Delta,testTime3UT1DeltaBullB);
-        return 9;
-    }
-
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeToMJD(void)
-{
-    psTime*  time = NULL;
-    psF64    mjd  = 0.0;
-
-    // Attempt to convert with time NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    mjd = psTimeToMJD(NULL);
-    if(!isnan(mjd)) {
-        psError(PS_ERR_UNKNOWN,true,"Expected NaN for NULL time");
-        return 1;
-    }
-
-    // Attempt to convert invalid time
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = 1;
-    time->nsec = 2e9;
-    time->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    mjd = psTimeToMJD(time);
-    if( !isnan(mjd)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NAN for invalid time");
-        return 2;
-    }
-
-    // Check valid time conversion to MJD after 1/1/1970 epoch
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    mjd = psTimeToMJD(time);
-    //    if(fabs(mjd - testTime1MJD) > ERROR_TOL) {
-    if(fabs(mjd - 53207.765929) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Expected MJD = %lf not as expected %lf",
-                mjd, testTime1MJD);
-        return 3;
-    }
-
-    // Check valid time conversion to MJD before 1/1/1970 epoch
-    time->sec = testTime4SecondsUTC;
-    time->nsec = testTime4NanosecondsUTC;
-    mjd = psTimeToMJD(time);
-    if(fabs(mjd - testTime4MJD) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Expected MJD = %lf not as expected %lf",
-                mjd, testTime4MJD);
-        return 4;
-    }
-
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeToJD(void)
-{
-    psTime*  time = NULL;
-    psF64    jd  = 0.0;
-
-    // Attempt to convert with time NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    jd = psTimeToJD(NULL);
-    if(!isnan(jd)) {
-        psError(PS_ERR_UNKNOWN,true,"Expected NaN for NULL time");
-        return 1;
-    }
-
-    // Attempt to convert invalid time
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = 1;
-    time->nsec = 2e9;
-    time->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    jd = psTimeToJD(time);
-    if( !isnan(jd)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NAN for invalid time");
-        return 2;
-    }
-
-    // Check valid time conversion to MJD after 1/1/1970 epoch
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    jd = psTimeToJD(time);
-    //    if(fabs(jd - testTime1JD) > ERROR_TOL) {
-    if(fabs(jd - 2453208.265929) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Expected JD = %lf not as expected %lf",
-                jd, testTime1JD);
-        return 3;
-    }
-
-    // Check valid time conversion to MJD before 1/1/1970 epoch
-    time->sec = testTime4SecondsUTC;
-    time->nsec = testTime4NanosecondsUTC;
-    jd = psTimeToJD(time);
-    if(fabs(jd - testTime4JD) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Expected JD = %lf not as expected %lf",
-                jd, testTime4JD);
-        return 4;
-    }
-
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeToISO(void)
-{
-    psTime*    time    = NULL;
-    char*      timeStr = NULL;
-
-    // Attempt to convert with NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL time");
-    timeStr = psTimeToISO(time);
-    if(timeStr != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 1;
-    }
-
-    // Attempt to convert invalid time
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = 1;
-    time->nsec = 2e9;
-    time->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    timeStr = psTimeToISO(time);
-    if( timeStr != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time");
-        return 2;
-    }
-
-    // Verify return NULL for time prior to year 0000
-    time->sec = testTime5SecondsUTC;
-    time->nsec = testTime5NanosecondsUTC;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for time prior year 0000");
-    timeStr = psTimeToISO(time);
-    if(timeStr != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for time prior to year 0000");
-        return 3;
-    }
-
-    // Verify return NULL for time after to year 9999
-    time->sec = testTime6SecondsUTC;
-    time->nsec = testTime6NanosecondsUTC;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for time after year 9999");
-    timeStr = psTimeToISO(time);
-    if(timeStr != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for time after to year 9999");
-        return 4;
-    }
-
-    // Verify return string with valid time
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    timeStr = psTimeToISO(time);
-    if(strcmp(timeStr,testTime1Str) != 0) {
-        psError(PS_ERR_UNKNOWN,true,"String %s not as expected %s",
-                timeStr, testTime1Str);
-        return 5;
-    }
-    psFree(timeStr);
-
-    // Verify return string with valid time and leap second set
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    time->leapsecond = true;
-    timeStr = psTimeToISO(time);
-    if(strcmp(timeStr,testTime1StrLeap) != 0) {
-        psError(PS_ERR_UNKNOWN,true,"String %s not as expected %s",
-                timeStr, testTime1StrLeap);
-        return 6;
-    }
-    psFree(timeStr);
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeToTimeval(void)
-{
-    psTime*           time         = NULL;
-    struct timeval*   timevalTime  = NULL;
-
-    // Attempt to convert with NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL time");
-    timevalTime = psTimeToTimeval(time);
-    if(timevalTime != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 1;
-    }
-
-    // Attempt to convert invalid time
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = 1;
-    time->nsec = 2e9;
-    time->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    timevalTime = psTimeToTimeval(time);
-    if( timevalTime != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time");
-        return 2;
-    }
-
-    // Attempt to convert invalid time
-    time->sec = -1;
-    time->nsec = 0;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    timevalTime = psTimeToTimeval(time);
-    if( timevalTime != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time");
-        return 2;
-    }
-
-    // Verify convert to timeval with valid time
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    timevalTime = psTimeToTimeval(time);
-    if(timevalTime->tv_sec != testTime1TimevalSec) {
-        psError(PS_ERR_UNKNOWN,true,"Timeval seconds %ld not as expectd %ld",
-                timevalTime->tv_sec,testTime1TimevalSec);
-        return 4;
-    }
-    if(timevalTime->tv_usec != testTime1TimevalUsec) {
-        psError(PS_ERR_UNKNOWN,true,"Timeval useconds %ld not as expected %ld",
-                timevalTime->tv_usec,testTime1TimevalUsec);
-        return 5;
-    }
-
-    psFree(timevalTime);
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromMJD(void)
-{
-    psTime*   time = NULL;
-
-    // Attempt to convert valid time to psTime
-    time = psTimeFromMJD(testTime1MJDTAI);
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Type %d not as expected %d",
-                time->type,PS_TIME_TAI);
-        return 1;
-    }
-    if(time->sec != testTime1SecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec,testTime1SecondsTAI);
-        return 2;
-    }
-    psFree(time);
-
-    // Attempt to convert valid time before 1970 epoch
-    time = psTimeFromMJD(testTime4MJD);
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Type %d not as expected %d",
-                time->type,PS_TIME_TAI);
-        return 3;
-    }
-    if(time->sec != testTime4SecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec,testTime4SecondsUTC);
-        return 4;
-    }
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromJD(void)
-{
-    psTime*   time = NULL;
-
-    // Attempt to convert valid time to psTime
-    time = psTimeFromJD(testTime1JDTAI);
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Type %d not as expected %d",
-                time->type,PS_TIME_TAI);
-        return 1;
-    }
-    if(time->sec != testTime1SecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec,(long int)testTime1SecondsTAI);
-        return 2;
-    }
-    psFree(time);
-
-    // Attempt to convert valid time before 1970 epoch
-    time = psTimeFromJD(testTime4JD);
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Type %d not as expected %d",
-                time->type,PS_TIME_TAI);
-        return 3;
-    }
-    if(time->sec != testTime4SecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec,testTime4SecondsUTC);
-        return 4;
-    }
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromISO(void)
-{
-    psTime*   time = NULL;
-
-    // Attempt to convert NULL string
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL ISO string");
-    time = psTimeFromISO(NULL, PS_TIME_TAI);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected for NULL ISO string");
-        return 1;
-    }
-
-    // Convert valid ISO string
-    time = psTimeFromISO(testTime1Str, PS_TIME_TAI);
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Type %d not as expected %d",
-                time->type, PS_TIME_TAI);
-        return 2;
-    }
-    if(time->sec != testTime1SecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec,testTime1SecondsTAI);
-        return 3;
-    }
-    psFree(time);
-
-    // Attempt to convert invalid ISO string
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error for invalid ISO string");
-    time = psTimeFromISO("Here I am", PS_TIME_TAI);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected for invalid ISO string");
-        return 4;
-    }
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromTimeval(void)
-{
-    psTime*          time        = NULL;
-    struct timeval*  timevalTime = NULL;
-
-    // Attempt to create psTime from NULL timeval ptr
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL timeval");
-    time = psTimeFromTimeval(NULL);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for NULL timeval ptr");
-        return 1;
-    }
-
-    // Convert valid timeval structure
-    timevalTime = (struct timeval*)psAlloc(sizeof(struct timeval));
-    timevalTime->tv_sec = testTime1SecondsTAI;
-    timevalTime->tv_usec = testTime1NanosecondsTAI / 1000;
-    time = psTimeFromTimeval(timevalTime);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return value for valid timeval");
-        return 2;
-    }
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"psTime type %d not as expected %d",
-                time->type, PS_TIME_TAI);
-        return 3;
-    }
-    if(time->sec != testTime1SecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                time->sec, testTime1SecondsTAI);
-        return 4;
-    }
-    if(time->nsec != testTime1NanosecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"psTime nanosec %ld not as expected %ld",
-                time->nsec, testTime1NanosecondsTAI);
-        return 5;
-    }
-    psFree(timevalTime);
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromTM(void)
-{
-    psTime*     time   = NULL;
-    struct tm*  tmTime = NULL;
-
-    // Attempt to convert from NULL tm structure ptr
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL tm ptr");
-    time = psTimeFromTM(tmTime);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for NULL tm ptr");
-        return 1;
-    }
-
-    // Verify convert for valid tm structure
-    tmTime = (struct tm*)psAlloc(sizeof(struct tm));
-    tmTime->tm_year = testTime7TmYear;
-    tmTime->tm_mon  = testTime7TmMon;
-    tmTime->tm_mday = testTime7TmDay;
-    tmTime->tm_hour = testTime7TmHour;
-    tmTime->tm_min  = testTime7TmMin;
-    tmTime->tm_sec  = testTime7TmSec;
-    time = psTimeFromTM(tmTime);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return value for valid tm structure");
-        return 2;
-    }
-    if(time->sec != testTime7Seconds) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec, (long int)testTime7Seconds);
-        return 3;
-    }
-    if(time->nsec != testTime7Nanoseconds) {
-        psError(PS_ERR_UNKNOWN,true,"psTime nanoseconds %ld not as expected %ld",
-                time->nsec, testTime7Nanoseconds);
-        return 4;
-    }
-    psFree(tmTime);
-    psFree(time);
-
-    // Verify convert for valid tm structure
-    tmTime = (struct tm*)psAlloc(sizeof(struct tm));
-    tmTime->tm_year = testTime8TmYear;
-    tmTime->tm_mon  = testTime8TmMon;
-    tmTime->tm_mday = testTime8TmDay;
-    tmTime->tm_hour = testTime8TmHour;
-    tmTime->tm_min  = testTime8TmMin;
-    tmTime->tm_sec  = testTime8TmSec;
-    time = psTimeFromTM(tmTime);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return value for valid tm structure");
-        return 2;
-    }
-    if(time->sec != testTime8Seconds) {
-        psError(PS_ERR_UNKNOWN,true,"psTime seconds %ld not as expected %ld",
-                (long int)time->sec, (long int)testTime8Seconds);
-        return 3;
-    }
-    if(time->nsec != testTime8Nanoseconds) {
-        psError(PS_ERR_UNKNOWN,true,"psTime nanoseconds %ld not as expected %ld",
-                time->nsec, testTime8Nanoseconds);
-        return 4;
-    }
-    psFree(tmTime);
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeConvert(void)
-{
-    psTime*  time1 = NULL;
-    psTime*  time2 = NULL;
-
-    // Attempt to convert NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    // Verify return value is NULL
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for NULL time specified");
-        return 1;
-    }
-
-    // Attempt to convert to invalid type
-    time1 = psTimeAlloc(PS_TIME_TAI);
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid type");
-    time2 = psTimeConvert(time1,-100);
-    // Verify return value is NULL
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for invalid type to convert to");
-        return 2;
-    }
-    time1->type = PS_TIME_UTC;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid type");
-    time2 = psTimeConvert(time1,-100);
-    // Verify return value is NULL
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for invalid type to convert to");
-        return 2;
-    }
-    time1->type = PS_TIME_TT;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid type");
-    time2 = psTimeConvert(time1,-100);
-    // Verify return value is NULL
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for invalid type to convert to");
-        return 2;
-    }
-    time1->type = -100;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid type");
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    // Verify return value is NULL
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for invalid type to convert to");
-        return 2;
-    }
-
-    // Attempt to convert with invalid time nsec > 1e9
-    time1->nsec = 2e9;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for invalid time specified");
-        return 3;
-    }
-
-    //Attempt to convert a time to the same type
-    time2 = NULL;
-    time1->sec = 1;
-    time1->nsec = 2;
-    time1->type = PS_TIME_TAI;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion to same type");
-        return 4;
-    }
-    // Verify time not changed
-    if((time2->sec != 1) || (time2->nsec != 2) || (time2->type != PS_TIME_TAI) ||
-            (time2->leapsecond != false) ) {
-        psError(PS_ERR_UNKNOWN,true,"Time member changes when no change expected");
-        return 5;
-    }
-
-    // Attempt to convert a UTC time to a TAI
-    time2 = NULL;
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-    time1->type = PS_TIME_UTC;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from UTC to TAI");
-        return 6;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_TAI);
-        return 7;
-    }
-    // Verify time is TAI as expected
-    if(time2->sec != testTime1SecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"TAI seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsTAI);
-        return 7;
-    }
-    if(time2->nsec != testTime1NanosecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"TAI nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsTAI);
-        return 8;
-    }
-
-    // Attempt to convert a UTC time to a TT
-    time2 = NULL;
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-    time1->type = PS_TIME_UTC;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_TT);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from UTC to TT");
-        return 6;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_TT) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_TT);
-        return 7;
-    }
-    // Verify time is TT as expected
-    if(time2->sec != testTime1SecondsTT) {
-        psError(PS_ERR_UNKNOWN,true,"TT seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsTT);
-        return 7;
-    }
-    if(time2->nsec != testTime1NanosecondsTT) {
-        psError(PS_ERR_UNKNOWN,true,"TT nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsTT);
-        return 8;
-    }
-
-    // Attempt to convert a UTC time to UT1
-    time2 = NULL;
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-    time1->type = PS_TIME_UTC;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_UT1);
-    if(time1 != time2) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from UTC to UT1");
-        return 9;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_UT1) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_UT1);
-        return 7;
-    }
-    // Verify time is UT1 as expected
-    if(time2->sec != testTime1SecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsUT1);
-        return 9;
-    }
-    if(time2->nsec != testTime1NanosecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 nanoseconds = %d not as expected %d",time2->nsec,
-                testTime1NanosecondsUT1);
-        return 10;
-    }
-
-    // Attempt to convert a TAI time to UTC
-    time2 = NULL;
-    time1->sec = testTime1SecondsTAI;
-    time1->nsec = testTime1NanosecondsTAI;
-    time1->type = PS_TIME_TAI;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_UTC);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TAI to UTC");
-        return 11;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_UTC);
-        return 7;
-    }
-    // Verify time is UTC as expected
-    if(time2->sec != testTime1SecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"UTC seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsUTC);
-        return 12;
-    }
-    if(time2->nsec != testTime1NanosecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"UTC nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsUTC);
-        return 13;
-    }
-
-    // Attempt to convert a TAI time to TT
-    time2 = NULL;
-    time1->sec = testTime1SecondsTAI;
-    time1->nsec = testTime1NanosecondsTAI;
-    time1->type = PS_TIME_TAI;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_TT);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TAI to TT");
-        return 14;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_TT) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_TT);
-        return 7;
-    }
-    // Verify time is TT as expected
-    if(time2->sec != testTime1SecondsTT) {
-        psError(PS_ERR_UNKNOWN,true,"TT seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsTT);
-        return 15;
-    }
-    if(time2->nsec != testTime1NanosecondsTT) {
-        psError(PS_ERR_UNKNOWN,true,"TT nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsTT);
-        return 16;
-    }
-
-    // Attempt to convert a TAI time to UT1
-    time2 = NULL;
-    time1->sec = testTime1SecondsTAI;
-    time1->nsec = testTime1NanosecondsTAI;
-    time1->type = PS_TIME_TAI;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_UT1);
-    if(time1 != time2) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TAI to UT1");
-        return 9;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_UT1) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_UT1);
-        return 7;
-    }
-    // Verify time is UT1 as expected
-    if(time2->sec != testTime1SecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsUT1);
-        return 9;
-    }
-    if(time2->nsec != testTime1NanosecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 nanoseconds = %d not as expected %d",time2->nsec,
-                testTime1NanosecondsUT1);
-        return 10;
-    }
-
-    // Attempt to convert a TT time to UTC
-    time2 = NULL;
-    time1->sec = testTime1SecondsTT;
-    time1->nsec = testTime1NanosecondsTT;
-    time1->type = PS_TIME_TT;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_UTC);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TT to UTC");
-        return 17;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_UTC);
-        return 7;
-    }
-    // Verify time is UTC as expected
-    if(time2->sec != testTime1SecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"UTC seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsUTC);
-        return 18;
-    }
-    if(time2->nsec != testTime1NanosecondsUTC) {
-        psError(PS_ERR_UNKNOWN,true,"UTC nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsUTC);
-        return 19;
-    }
-
-    // Attempt to convert a TT time to TAI
-    time2 = NULL;
-    time1->sec = testTime1SecondsTT;
-    time1->nsec = testTime1NanosecondsTT;
-    time1->type = PS_TIME_TT;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_TAI);
-    if(time2 != time1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TT to TAI");
-        return 20;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_TAI);
-        return 7;
-    }
-    // Verify time is TAI as expected
-    if(time2->sec != testTime1SecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"TAI seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsTAI);
-        return 21;
-    }
-    if(time2->nsec != testTime1NanosecondsTAI) {
-        psError(PS_ERR_UNKNOWN,true,"TT nanoseconds = %ld not as expected %ld",(long int)time2->nsec,
-                (long int)testTime1NanosecondsTAI);
-        return 22;
-    }
-
-    // Attempt to convert a TT time to UT1
-    time2 = NULL;
-    time1->sec = testTime1SecondsTT;
-    time1->nsec = testTime1NanosecondsTT;
-    time1->type = PS_TIME_TT;
-    time1->leapsecond = false;
-    time2 = psTimeConvert(time1,PS_TIME_UT1);
-    if(time1 != time2) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from TT to UT1");
-        return 9;
-    }
-    // Verify time type
-    if(time2->type != PS_TIME_UT1) {
-        psError(PS_ERR_UNKNOWN,true,"Returned time type %d not as expected %d",
-                time2->type, PS_TIME_UT1);
-        return 7;
-    }
-    // Verify time is UT1 as expected
-    if(time2->sec != testTime1SecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 seconds = %ld not as expected %ld",(long int)time2->sec,
-                (long int)testTime1SecondsUT1);
-        return 9;
-    }
-    if(time2->nsec != testTime1NanosecondsUT1) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 nanoseconds = %d not as expected %d",time2->nsec,
-                testTime1NanosecondsUT1);
-        return 10;
-    }
-
-    // Attempt to convert from UT1 to TAI, UTC, TT
-    time2 = NULL;
-    time1->sec = 1;
-    time1->nsec = 2;
-    time1->type = PS_TIME_UT1;
-    time1->leapsecond = false;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message converting from UT1");
-    time2 = psTimeConvert(time1,PS_TIME_UTC);
-    if(time2 != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return time for conversion from UT1");
-        return 23;
-    }
-
-    psFree(time1);
-
-    return 0;
-}
-
-//psS32 testTimeOther(void)
-//{
-//    psTime *testTime;
-//    char *testString = "2004-07-21T18:22:24.272Z";
-//
-//    psLibInit("pslib.config");
-//
-// Test time was taken at July 21, 2004 at 18:22:24.272044
-//    testTime = (psTime*)psAlloc(sizeof(psTime));
-//    testTime->sec = 1090434144;
-//    testTime->nsec = 272044000;
-//    testTime->type = PS_TIME_TAI;
-
-// Test O - psTime to LMST
-//    printPositiveTestHeader(stdout, "psTime", "Convert psTime time to LST");
-//    char *testString2 = "2004-09-10T1:00:00.00Z";
-//    psTime* testTime2 = NULL;
-//    testTime2 = psTimeFromISO(testString2);
-//    double dblTime = psTimeToLMST(testTime2, 1);
-//    printf("LST (rad): %lf\n", dblTime);
-//    psFree(testTime2);
-//    printFooter(stdout, "psTime", "Convert psTime time to LST", true);
-
-
-//    return 0;
-//}
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psTime_02.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psTime_02.c	(revision 30117)
+++ 	(revision )
@@ -1,368 +1,0 @@
-/** @file  tst_psTime_02.c
- *
- *  @brief Test driver for psTime functions
- *
- *  This test driver contains the following tests for psTime:
- *     1) Convert psTime to Local Mean Sidereal Time (LMST)
- *     2) Calculate leap second delta between times
- *     3) Creation of psTime of type TT
- *     4) Creation of psTime of type UTC
- *
- *  @author  Ross Harman, MHPCC
- *  @author  Eric Van Alst, MHPCC
- *
- *  @version $Revision: 1.3 $  $Name: not supported by cvs2svn $
- *  @date  $Date: 2006-01-31 23:24:21 $
- *
- *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
- *
- */
-
-#include "pslib_strict.h"
-#include "psTest.h"
-
-#define ERROR_TOL  0.001
-
-static psS32 testTimeLMST(void);
-static psS32 testTimeLeapSecondDelta(void);
-static psS32 testTimeIsLeapSecond(void);
-static psS32 testTimeFromTT(void);
-static psS32 testTimeFromUTC(void);
-
-// Test Time 1 : May 9, 2005  00:00:00,0
-//               MJD = 53499.000
-//               JD = 2453499.5
-// UTC Test Time 1
-const psS64 testTime1SecondsUTC     = 1115596900;
-const psU32 testTime1NanosecondsUTC = 0;
-// Expected LMST  15:09:18
-const psF64 testTime1LMST0          = 3.967604;
-
-// Test Time 2 : May 9, 1995 00:00:00,0
-//               MJD = 49846.00
-//               JD = 2449846.5
-// UTC Test Time 2
-const psS64 testTime2SecondsUTC     = 799977600;
-const psU32 testTime2NanosecondsUTC = 0;
-// Expected leap second delta
-const psS64 testTimeLeapSecondDelta1 = 3;
-
-// Test Time 3: Jan 1, 1999 00:00:00,0
-//              MJD = 51179
-//              JD = 2451179.5
-const psS64 testTime3SecondsUTC     = 915148800;
-const psU32 testTime3NanosecondsUTC = 0;
-
-testDescription tests[] = {
-                              {testTimeLMST,1,"psTimeToLMST",0,false},
-                              {testTimeLeapSecondDelta,2,"psTimeLeapSecondDelta",0,false},
-                              {testTimeIsLeapSecond,6,"psTimeIsLeapSecond",0,false},
-                              {testTimeFromTT,66,"psTimeFromTT",0,false},
-                              {testTimeFromUTC,666,"psTimeFromUTC",0,false},
-                              {NULL}
-                          };
-psS32 main(psS32 argc, char* argv[])
-{
-    psLogSetLevel(PS_LOG_INFO);
-
-    // Initialize library internal structures
-    psLibInit("pslib.config");
-
-    if( !runTestSuite(stderr,"psTime",tests,argc,argv)) {
-        return 1;
-    }
-
-    // Clean up library
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeLMST(void)
-{
-    psTime*       time      = NULL;
-    psF64         lmst      = 0.0;
-
-    // Attempt to get LMST with NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    lmst = psTimeToLMST(time,0);
-    if(!isnan(lmst)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NaN as expected %lf",lmst);
-        return 1;
-    }
-
-    // Attempt to get LMST with valid test time
-    // Allocate test time
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    time->leapsecond = false;
-    lmst = psTimeToLMST(time,0.0);
-    if(fabs(lmst-testTime1LMST0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"LMST %lf not as expected %lf",lmst,testTime1LMST0);
-        return 2;
-    }
-
-    // Attempt to get LMST with invalid input time UT1
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for incorrect type");
-    time->type = PS_TIME_UT1;
-    lmst = psTimeToLMST(time,0.0);
-    if(!isnan(lmst)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NaN as expected %lf",lmst);
-        return 3;
-    }
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeLeapSecondDelta(void)
-{
-    psTime*       time1   = NULL;
-    psTime*       time2   = NULL;
-    psS64         delta   = 0;
-
-    // Attempt to get delta with NULL time1 argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    delta = psTimeLeapSecondDelta(time1,time2);
-    if(delta != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Delta of %ld not as expected 0",(long int)delta);
-        return 1;
-    }
-
-    // Set test time 1
-    time1 = psTimeAlloc(PS_TIME_UTC);
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-    time1->leapsecond = false;
-
-    // Attempt to get delta with NULL time2 argument
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    delta = psTimeLeapSecondDelta(time1,time2);
-    if(delta != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Delta of %ld not as expected 0",(long int)delta);
-        return 2;
-    }
-
-    // Set test time 2 with invalid time
-    time2 = psTimeAlloc(PS_TIME_UTC);
-    time2->sec = 0;
-    time2->nsec = 2e9;
-    time2->leapsecond = false;
-
-    // Attempt to get delta with invalid time2
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    delta = psTimeLeapSecondDelta(time1,time2);
-    if(delta != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Delta of %ld not as expected 0",(long int)delta);
-        return 3;
-    }
-
-    // Set test time 2 valid
-    time2->sec = testTime2SecondsUTC;
-    time2->nsec = testTime2NanosecondsUTC;
-
-    // Set test time 1 invalid
-    time1->sec = 0;
-    time1->nsec = 2e9;
-
-    // Attempt to get delta with invalid time1
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    delta = psTimeLeapSecondDelta(time1,time2);
-    if(delta != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Delta of %ld not as expected 0",(long int)delta);
-        return 4;
-    }
-
-    // Set test time 1 to greater time
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-    delta = psTimeLeapSecondDelta(time1,time2);
-    if(delta != testTimeLeapSecondDelta1) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %ld not as expected %ld",
-                (long int)delta,(long int)testTimeLeapSecondDelta1);
-        return 5;
-    }
-
-    // Set test time 1 to lesser time
-    delta = psTimeLeapSecondDelta(time2,time1);
-    if(delta != testTimeLeapSecondDelta1) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %ld not as expected %ld",
-                (long int)delta,(long int)testTimeLeapSecondDelta1);
-        return 6;
-    }
-
-    // Attempt to get delta with times equal
-    delta = psTimeLeapSecondDelta(time1,time1);
-    if(delta != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %ld not as expected 0",(long int)delta);
-        return 7;
-    }
-
-    psFree(time2);
-    psFree(time1);
-
-    return 0;
-}
-
-psS32 testTimeIsLeapSecond(void)
-{
-    psTime*     time        = NULL;
-    psBool      leapsecond  = false;
-
-    // Attempt to determine if leap second with NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL time");
-    leapsecond = psTimeIsLeapSecond(time);
-    if(leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 0",leapsecond);
-        return 1;
-    }
-
-    // Set time
-    time = psTimeAlloc(PS_TIME_TAI);
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    time->leapsecond = false;
-
-    // Attempt to determine if leap second with non-UTC time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid type");
-    leapsecond = psTimeIsLeapSecond(time);
-    if(leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 0",leapsecond);
-        return 2;
-    }
-
-    // Set time to UTC
-    time->type = PS_TIME_UTC;
-
-    // Attempt to determine if leap second with valid time
-    leapsecond = psTimeIsLeapSecond(time);
-    if(leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not a expected 0",leapsecond);
-        return 3;
-    }
-
-    // Set time to UTC with leap second
-    time->sec = testTime3SecondsUTC;
-    time->nsec = testTime3NanosecondsUTC;
-    leapsecond = psTimeIsLeapSecond(time);
-    if(!leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 1",leapsecond);
-        //        return 4;
-    }
-
-    // Set time to 1 second before a known leap second
-    time->sec--;
-    leapsecond = psTimeIsLeapSecond(time);
-    if(leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 0",leapsecond);
-        return 5;
-    }
-
-    // Set time to 1 second after a known leap second
-    time->sec +=2;
-    leapsecond = psTimeIsLeapSecond(time);
-    if(leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 0",leapsecond);
-        return 6;
-    }
-
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromTT(void)
-{
-    psTime*       time = NULL;
-
-    // Attempt to create psTime with invalid time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    time = psTimeFromTT(0,2e9);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 1;
-    }
-
-    // Attempt to create psTime with valid time
-    time = psTimeFromTT(testTime1SecondsUTC,testTime1NanosecondsUTC);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Return NULL when not expected");
-        return 2;
-    }
-    if(time->type != PS_TIME_TT) {
-        psError(PS_ERR_UNKNOWN,true,"Type of time object %d not as expected %d",
-                time->type,PS_TIME_TT);
-        return 3;
-    }
-    if((time->sec != testTime1SecondsUTC) || (time->nsec != testTime1NanosecondsUTC)) {
-        psError(PS_ERR_UNKNOWN,true,"Seconds %ld nanoseconds %d not as expected seconds %ld nanoseconds %d",
-                (long int)time->sec,time->nsec,(long int)testTime1SecondsUTC,testTime1NanosecondsUTC);
-        return 4;
-    }
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeFromUTC(void)
-{
-    psTime*       time = NULL;
-
-    // Attempt to create psTime with invalid time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid time");
-    time = psTimeFromUTC(0,2e9,true);
-    if(time != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL as expected");
-        return 1;
-    }
-
-    // Attempt to create psTime with valid non-leapsecond time and leapsecond flag true
-    time = psTimeFromUTC(testTime1SecondsUTC,testTime1NanosecondsUTC,true);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Return NULL when not expected");
-        return 2;
-    }
-    if(time->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"Type of time object %d not as expected %d",
-                time->type,PS_TIME_UTC);
-        return 3;
-    }
-    if((time->sec != testTime1SecondsUTC) || (time->nsec != testTime1NanosecondsUTC)) {
-        psError(PS_ERR_UNKNOWN,true,"Seconds %ld nanoseconds %d not as expected seconds %ld nanoseconds %d",
-                (long int)time->sec,time->nsec,(long int)testTime1SecondsUTC,testTime1NanosecondsUTC);
-        return 4;
-    }
-    if(time->leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 0",time->leapsecond);
-        return 5;
-    }
-    psFree(time);
-
-    // Attempt to create psTime with valid leapsecond time but leapsecond flag false
-    time = psTimeFromUTC(testTime3SecondsUTC,testTime3NanosecondsUTC,false);
-    if(time == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Return NULL when not expected");
-        return 6;
-    }
-    if(time->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"Type of time object %d not as expected %d",
-                time->type,PS_TIME_UTC);
-        return 7;
-    }
-    if((time->sec != testTime3SecondsUTC) || (time->nsec != testTime3NanosecondsUTC)) {
-        psError(PS_ERR_UNKNOWN,true,"Seconds %ld nanoseconds %d not as expected seconds %ld nanoseconds %d",
-                (long int)time->sec,time->nsec,(long int)testTime1SecondsUTC,testTime1NanosecondsUTC);
-        return 8;
-    }
-    if(!time->leapsecond) {
-        psError(PS_ERR_UNKNOWN,true,"Leapsecond flag %d not as expected 1",time->leapsecond);
-        return 9;
-    }
-
-
-    psFree(time);
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psTime_03.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psTime_03.c	(revision 30117)
+++ 	(revision )
@@ -1,505 +1,0 @@
-/** @file  tst_psTime_03.c
- *
- *  @brief Test driver for psTime functions
- *
- *  This test driver contains the following tests for psTime:
- *   1) psTimeMath invalid times
- *   2) psTimeMath valid time of different types
- *   3) psTimeDelta valid times with different types
- *
- *  @author  Ross Harman, MHPCC
- *  @author  Eric Van Alst, MHPCC
- *
- *  @version $Revision: 1.4 $  $Name: not supported by cvs2svn $
- *  @date  $Date: 2006-06-27 20:33:22 $
- *
- *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
- *
- */
-
-#include "pslib_strict.h"
-#include "psTest.h"
-#include <string.h>
-
-#define ERROR_TOL    0.001
-
-static psS32 testTimeMath(void);
-static psS32 testTimeDelta(void);
-static psS32 testTimeConvert1(void);
-
-// Test Time 1 : May 9, 2005 00:00:00,0
-//               MJD = 53499.00
-//               JD = 2453499.5
-// UTC Test Time 1
-const psS64 testTime1SecondsUTC         = 1115596900;
-const psU32 testTime1NanosecondsUTC     = 0;
-// TAI Test Time 1
-const psS64 testTime1SecondsTAI         = 1115596932;
-const psU32 testTime1NanosecondsTAI     = 0;
-// TT Test Time 1
-const psS64 testTime1SecondsTT          = 1115596964;
-const psU32 testTime1NanosecondsTT      = 184000000;
-// UT1 Test Time 1
-const psS64 testTime1SecondsUT1         = 1115596900;
-const psU32 testTime1NanosecondsUT1     = 184000000;
-// Delta 1
-const psF64 deltaTime1                  = -15.5;
-// Expected UTC Time 1
-const psS64 newTestTime1SecondsUTC      = 1115596884;
-const psU32 newTestTime1NanosecondsUTC  = 500000000;
-// Expected TAI Time 1
-const psS64 newTestTime1SecondsTAI      = 1115596916;
-const psU32 newTestTime1NanosecondsTAI  = 500000000;
-// Delta 2
-const psF64 deltaTime2                  = 123.066;
-// Expected TT Time 1 w/ delta 2
-const psS64 newTestTime1SecondsTT       = 1115597087;
-const psU32 newTestTime1NanosecondsTT   = 250000000;
-// Expected UT1 Time 1 w/ delta 2
-const psS64 newTestTime1SecondsUT1      = 1115597023;
-const psU32 newTestTime1NanosecondsUT1  = 250000000;
-
-// Test Time 2 : Dec. 31 1998 23:59:45,0
-//               MJD = 51178.99983
-//               JD = 2451179.49983
-// UTC Test Time 1
-const psS64 testTime2SecondsUTC         = 915148785;
-const psU32 testTime2NanosecondsUTC     = 0;
-// Delta 3
-const psF64 deltaTime3                    = 30.0;
-// Expected UTC Time
-const psS64 newTestTime2SecondsUTC      = 915148814;
-const psU32 newTestTime2NanosecondsUTC  = 0;
-
-// Appendix B time conversion tests
-//
-#define APPB_TESTS    8
-const psS64 testTimeBSeconds[APPB_TESTS] =
-    {
-        915148829,
-        915148829,
-        915148830,
-        915148830,
-        915148831,
-        915148831,
-        915148832,
-        915148832
-    };
-const psU32 testTimeBNanoseconds[APPB_TESTS] =
-    {
-        0,
-        500000000,
-        0,
-        500000000,
-        0,
-        500000000,
-        0,
-        500000000
-    };
-const psBool testTimeBLeapsecond[APPB_TESTS] =
-    {
-        false,
-        false,
-        false,
-        false,
-        true,
-        true,
-        false,
-        false
-    };
-// Expected results
-const char* testTimeBStrUTC[APPB_TESTS] =
-    {
-        "1998-12-31T23:59:58.0Z",
-        "1998-12-31T23:59:58.5Z",
-        "1998-12-31T23:59:59.0Z",
-        "1998-12-31T23:59:59.5Z",
-        "1998-12-31T23:59:60.0Z",
-        "1998-12-31T23:59:60.5Z",
-        "1999-01-01T00:00:00.0Z",
-        "1999-01-01T00:00:00.5Z"
-    };
-const char* testTimeBStrTAI[APPB_TESTS] =
-    {
-        "1999-01-01T00:00:29.0Z",
-        "1999-01-01T00:00:29.5Z",
-        "1999-01-01T00:00:30.0Z",
-        "1999-01-01T00:00:30.5Z",
-        "1999-01-01T00:00:31.0Z",
-        "1999-01-01T00:00:31.5Z",
-        "1999-01-01T00:00:32.0Z",
-        "1999-01-01T00:00:32.5Z"
-    };
-const char* testTimeBStrTT[APPB_TESTS] =
-    {
-        "1999-01-01T00:01:01.1Z",
-        "1999-01-01T00:01:01.6Z",
-        "1999-01-01T00:01:02.1Z",
-        "1999-01-01T00:01:02.6Z",
-        "1999-01-01T00:01:03.1Z",
-        "1999-01-01T00:01:03.6Z",
-        "1999-01-01T00:01:04.1Z",
-        "1999-01-01T00:01:04.6Z"
-    };
-const char* testTimeBStrUT1[APPB_TESTS] =
-    {
-        "1998-12-31T23:59:58.7Z",
-        "1998-12-31T23:59:59.2Z",
-        "1998-12-31T23:59:59.7Z",
-        "1998-12-31T23:59:60.2Z",
-        "1998-12-31T23:59:60.7Z",
-        "1999-01-01T00:00:00.2Z",
-        "1999-01-01T00:00:00.7Z",
-        "1999-01-01T00:00:01.2Z"
-    };
-
-// Test Time B1 : Dec 31, 1998 23:59:58,0
-//                MJD = 51178.99998
-//                JD = 2451179.49998
-//const psS64 testTimeB1SecondsUTC        = 915148798;
-//const psU32 testTimeB1NanosecondsUTC    = 0;
-// Expected ISO times
-//const char testTimeB1StrUTC[] = "1998-12-31T23:59:58,0Z";
-//const char testTimeB1StrTAI[] = "1999-01-01T00:00:29,0Z";
-//const char testTimeB1StrTT[]  = "1999-01-01T00:01:01,1Z";
-//const char testTimeB1StrUT1[] = "1998-12-31T23:59:57,7Z";
-//
-// Test Time B2 : Dec 31, 1998 23:59:58,5
-//
-//
-//const psS64 testTimeB2SecondsUTC       = 915148798;
-//const psU32 testTimeB2NanosecondsUTC   = 500000000;
-// Expected ISO times
-//const char testTimeB2StrUTC[] = "1998-12-31T23:59:58,5Z";
-//const char testTimeB2StrTAI[] = "1991-01-01T00:00:29,5Z";
-//const char testTimeB2StrTT[]  = "1999-01-01T00:01:01,6Z";
-//const char testTimeB2StrUT1[] = "1998-12-31T23:59:58,2Z";
-
-testDescription tests[] = {
-                              {testTimeMath,1,"psTimeMath",0,false},
-                              {testTimeDelta,2,"psTimeDelta",0,false},
-                              {testTimeConvert1,666,"psTimeConvert",0,false},
-                              {NULL}
-                          };
-
-psS32 main(psS32 argc, char* argv[])
-{
-    psLogSetLevel(PS_LOG_INFO);
-
-    // Initialize library internal structures
-    psLibInit("pslib.config");
-
-    if( !runTestSuite(stderr,"psTime",tests,argc,argv)) {
-        return 1;
-    }
-
-    // Clean up library
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeMath(void)
-{
-    psTime*     time      = NULL;
-    psTime*     newTime   = NULL;
-
-    // Attempt to perform math operation on NULL time
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL time");
-    if(psTimeMath(time,-1.1) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for NULL time");
-        return 1;
-    }
-
-    // Set up input time with invalid nanoseconds
-    time = psTimeAlloc(PS_TIME_UTC);
-    time->sec = 0;
-    time->nsec = 2e9;
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid time");
-    if(psTimeMath(time,-1.1) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return NULL for invalid time");
-        return 2;
-    }
-
-    // Set up input time with valid time
-    time->sec = testTime1SecondsUTC;
-    time->nsec = testTime1NanosecondsUTC;
-    newTime = psTimeMath(time,deltaTime1);
-    if(newTime == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return");
-        return 3;
-    }
-    if(newTime->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"New time type %d not as expected %d",
-                newTime->type,PS_TIME_UTC);
-        return 4;
-    }
-    if((newTime->sec != newTestTime1SecondsUTC) || (newTime->nsec != newTestTime1NanosecondsUTC)) {
-        psError(PS_ERR_UNKNOWN,true,"UTC sec %ld nsec %d not as expected sec %ld nsec %d",
-                (long int)newTime->sec,newTime->nsec,(long int)newTestTime1SecondsUTC,
-                newTestTime1NanosecondsUTC);
-        return 5;
-    }
-    psFree(newTime);
-
-    // Set up input time with valid TAI time
-    time->sec = testTime1SecondsTAI;
-    time->nsec = testTime1NanosecondsTAI;
-    time->type = PS_TIME_TAI;
-    newTime = psTimeMath(time,deltaTime1);
-    if(newTime == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return");
-        return 3;
-    }
-    if(newTime->type != PS_TIME_TAI) {
-        psError(PS_ERR_UNKNOWN,true,"New time type %d not as expected %d",
-                newTime->type,PS_TIME_TAI);
-        return 4;
-    }
-    if((newTime->sec != newTestTime1SecondsTAI) || (newTime->nsec != newTestTime1NanosecondsTAI)) {
-        psError(PS_ERR_UNKNOWN,true,"TAI sec %ld nsec %d not as expected sec %ld nsec %d",
-                (long int)newTime->sec,newTime->nsec,(long int)newTestTime1SecondsTAI,
-                newTestTime1NanosecondsTAI);
-        return 5;
-    }
-    psFree(newTime);
-
-    // Set up input time with valid TT time
-    time->sec = testTime1SecondsTT;
-    time->nsec = testTime1NanosecondsTT;
-    time->type = PS_TIME_TT;
-    newTime = psTimeMath(time,deltaTime2);
-    if(newTime == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return");
-        return 3;
-    }
-    if(newTime->type != PS_TIME_TT) {
-        psError(PS_ERR_UNKNOWN,true,"New time type %d not as expected %d",
-                newTime->type,PS_TIME_TT);
-        return 4;
-    }
-    if((newTime->sec != newTestTime1SecondsTT) || (newTime->nsec != newTestTime1NanosecondsTT)) {
-        psError(PS_ERR_UNKNOWN,true,"TT sec %ld nsec %d not as expected sec %ld nsec %d",
-                (long int)newTime->sec,newTime->nsec,(long int)newTestTime1SecondsTT,
-                newTestTime1NanosecondsTT);
-        return 5;
-    }
-    psFree(newTime);
-
-    // Set up input time with valid TT time
-    time->sec = testTime1SecondsUT1;
-    time->nsec = testTime1NanosecondsUT1;
-    time->type = PS_TIME_UT1;
-    newTime = psTimeMath(time,deltaTime2);
-    if(newTime == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return");
-        return 3;
-    }
-    if(newTime->type != PS_TIME_UT1) {
-        psError(PS_ERR_UNKNOWN,true,"New time type %d not as expected %d",
-                newTime->type,PS_TIME_UT1);
-        return 4;
-    }
-    if((newTime->sec != newTestTime1SecondsUT1) || (newTime->nsec != newTestTime1NanosecondsUT1)) {
-        psError(PS_ERR_UNKNOWN,true,"UT1 sec %ld nsec %d not as expected sec %ld nsec %d",
-                (long int)newTime->sec,newTime->nsec,(long int)newTestTime1SecondsUT1,
-                newTestTime1NanosecondsUT1);
-        return 5;
-    }
-    psFree(newTime);
-
-    // Set up input time with valid UTC time and delt which crosses leap second
-    time->sec = testTime2SecondsUTC;
-    time->nsec = testTime2NanosecondsUTC;
-    time->type = PS_TIME_UTC;
-    newTime = psTimeMath(time,deltaTime3);
-    if(newTime == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return");
-        return 3;
-    }
-    if(newTime->type != PS_TIME_UTC) {
-        psError(PS_ERR_UNKNOWN,true,"New time type %d not as expected %d",
-                newTime->type,PS_TIME_UTC);
-        return 4;
-    }
-    if((newTime->sec != newTestTime2SecondsUTC) || (newTime->nsec != newTestTime2NanosecondsUTC)) {
-        psError(PS_ERR_UNKNOWN,true,"UTC sec %ld nsec %d not as expected sec %ld nsec %d",
-                (long int)newTime->sec,newTime->nsec,(long int)newTestTime2SecondsUTC,
-                newTestTime2NanosecondsUTC);
-        return 5;
-    }
-    psFree(newTime);
-
-    psFree(time);
-
-    return 0;
-}
-
-psS32 testTimeDelta(void)
-{
-    psTime*   time1   = NULL;
-    psTime*   time2   = NULL;
-    psF64     delta   = 0.0;
-
-    // Attempt to get delta with time1 NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL time");
-    delta = psTimeDelta(time1,time2);
-    if(fabs(delta-0.0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for NULL time argument");
-        return 1;
-    }
-
-    // Set time 1
-    time1 = psTimeAlloc(PS_TIME_UTC);
-
-    // Attempt to get delta with time2 NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL time");
-    delta = psTimeDelta(time1,time2);
-    if(fabs(delta-0.0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for NULL time argument");
-        return 2;
-    }
-
-    // Set time 2
-    time2 = psTimeAlloc(PS_TIME_UTC);
-
-    // Set time1 invalid
-    time1->sec = 0;
-    time1->nsec = 2e9;
-    // Attempt to get delta with time1 invalid
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid time");
-    delta = psTimeDelta(time1,time2);
-    if(fabs(delta-0.0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for invalid time argument");
-        return 3;
-    }
-
-    // Set time 1 valid
-    time1->sec = testTime1SecondsUTC;
-    time1->nsec = testTime1NanosecondsUTC;
-
-    // Set time 2 invalid
-    time2->sec = 0;
-    time2->nsec = 2e9;
-    // Attempt to get delta with time2 invalid
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid time");
-    delta = psTimeDelta(time1,time2);
-    if(fabs(delta-0.0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for invalid time argument");
-        return 4;
-    }
-
-    // Set time 2 valid but different type
-    time2->sec = newTestTime1SecondsUTC;
-    time2->nsec = newTestTime1NanosecondsUTC;
-    time2->type = PS_TIME_TAI;
-    // Attempt to get delta with different time types
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for incorrect type");
-    delta = psTimeDelta(time1,time2);
-    if(fabs(delta-0.0) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return 0 for invalid time argument");
-        return 5;
-    }
-
-    // Set time 2 to same as time 1
-    time2->type = PS_TIME_UTC;
-    // Attempt to get delta with valid times of the same type
-    delta = psTimeDelta(time2,time1);
-    if(fabs(delta-deltaTime1) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %lf not as expected %lf",
-                delta,deltaTime1);
-        return 6;
-    }
-
-    // Set time 1 and 2 as different times with same type
-    time1->sec = testTime1SecondsTT;
-    time1->nsec = testTime1NanosecondsTT;
-    time1->type = PS_TIME_TT;
-    time2->sec = newTestTime1SecondsTT;
-    time2->nsec = newTestTime1NanosecondsTT;
-    time2->type = PS_TIME_TT;
-    // Attempt to get delta with valid times of the same type
-    delta = psTimeDelta(time2,time1);
-    if(fabs(delta-deltaTime2) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %lf not as expected %lf",
-                delta,deltaTime2);
-        return 7;
-    }
-
-    // Set time 1 and 2 as different times with same type
-    time1->sec = testTime2SecondsUTC;
-    time1->nsec = testTime2NanosecondsUTC;
-    time1->type = PS_TIME_UTC;
-    time2->sec = newTestTime2SecondsUTC;
-    time2->nsec = newTestTime2NanosecondsUTC;
-    time2->type = PS_TIME_UTC;
-    // Attempt to get delta with valid times of the same type
-    delta = psTimeDelta(time2,time1);
-    if(fabs(delta-deltaTime3) > ERROR_TOL) {
-        psError(PS_ERR_UNKNOWN,true,"Delta %lf not as expected %lf",
-                delta,deltaTime3);
-        return 7;
-    }
-
-    psFree(time1);
-    psFree(time2);
-
-    return 0;
-}
-
-psS32 testTimeConvert1(void)
-{
-    psTime*     time    = NULL;
-    char*       timeStr = NULL;
-
-    for(psS32 i = 0; i < APPB_TESTS; i++) {
-
-        // Initialize time for test time B1
-        time = psTimeAlloc(PS_TIME_TAI);
-        time->sec = testTimeBSeconds[i];
-        time->nsec = testTimeBNanoseconds[i];
-
-        // Verify TAI ISO string
-        timeStr = psTimeToISO(time);
-        if(strcmp(timeStr,testTimeBStrTAI[i]) != 0) {
-            psError(PS_ERR_UNKNOWN,true,"TAI ISO string %s not as expected %s",timeStr,testTimeBStrTAI[i]);
-            return i+1;
-        }
-        psFree(timeStr);
-
-        time = psTimeConvert(time,PS_TIME_TT);
-        timeStr = psTimeToISO(time);
-        if(strcmp(timeStr,testTimeBStrTT[i]) != 0) {
-            psError(PS_ERR_UNKNOWN,true,"TT ISO string %s not as expected %s",timeStr,testTimeBStrTT[i]);
-            return i+10;
-        }
-        psFree(timeStr);
-
-        // Verify UTC ISO string
-        time = psTimeConvert(time,PS_TIME_UTC);
-        time->leapsecond = testTimeBLeapsecond[i];
-        timeStr = psTimeToISO(time);
-        if(strcmp(timeStr,testTimeBStrUTC[i]) != 0) {
-            if(strncmp(timeStr,"1999-01-01T00:00:60.0Z", 10) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"UTC ISO string %s not as expected %s",timeStr,testTimeBStrUTC[i]);
-                return i+20;
-            }
-        }
-        psFree(timeStr);
-
-        time = psTimeConvert(time,PS_TIME_UT1);
-        timeStr = psTimeToISO(time);
-        if(strcmp(timeStr,testTimeBStrUT1[i]) != 0) {
-            if(strncmp(timeStr,"1999-01-01T00:00:60.2Z", 10) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"UT1 ISO string %s not as expected %s",timeStr,testTimeBStrUT1[i]);
-                return i+30;
-            }
-        }
-        psFree(timeStr);
-
-        psFree(time);
-    }
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/astro/tst_psTime_04.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/astro/tst_psTime_04.c	(revision 30117)
+++ 	(revision )
@@ -1,177 +1,0 @@
-/** @file  tst_psTime_04.c
- *
- *  @brief Test driver for psTime functions
- *
- *  This test driver contains the following tests for psTime:
- *      Test A - Initialize time
- *      Test B - Attempt to open non-existant time config file
- *      Test C - Attempt to open non-existant time data files
- *      Test D - Attempt to read incorrect number of files
- *      Test E - Attempt to read incorrect number of from values
- *      Test F - Attempt to read data file with typo in number
- *      Test G - Free data
- *      Test H - Attempt to use all timer functions
- *      Test I - Tidal Corrections to UT1-UTC
- *
- *  @author  Ross Harman, MHPCC
- *  @author  Eric Van Alst, MHPCC
- *  @author  David Robbins, MHPCC
- *
- *  @version $Revision: 1.9 $  $Name: not supported by cvs2svn $
- *  @date  $Date: 2006-01-31 23:24:21 $
- *
- *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
- *
- */
-#include "config.h"
-
-#include "pslib_strict.h"
-#include "psTest.h"
-
-static psS32 testTimeInit1(void);
-static psS32 testTimeInit2(void);
-static psS32 testTimeInit3(void);
-static psS32 testTimeInit4(void);
-static psS32 testTimeInit5(void);
-static psS32 testTimeInit6(void);
-static psS32 testTimer1(void);
-static psS32 testTideUT1Corr(void);
-
-testDescription tests[] = {
-                              {testTimeInit1,1,"p_psTimeInit",0,false},
-                              {testTimeInit2,2,"p_psTimeInit",0,false},
-                              {testTimeInit3,3,"p_psTimeInit",0,false},
-                              {testTimeInit4,4,"p_psTimeInit",0,false},
-                              {testTimeInit5,5,"p_psTimeInit",0,false},
-                              {testTimeInit6,6,"p_psTimeInit",0,false},
-                              {testTimer1,8,"psTimer",0,false},
-                              {testTideUT1Corr,9,"psTime_TideUT1Corr",0,false},
-                              {NULL}
-                          };
-
-psS32 main(psS32 argc, char* argv[])
-{
-    if(!runTestSuite(stderr,"psTime",tests,argc,argv)) {
-        return 1;
-    }
-
-    return 0;
-}
-
-psS32 testTimeInit1(void)
-{
-    // Test A - Initialize time
-    psLibInit("pslib.config");
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeInit2(void)
-{
-    // Test B - Attempt to open non-existant time config file
-    psLibInit("zzz");
-
-    return 0;
-}
-
-psS32 testTimeInit3(void)
-{
-    // Test C - Attempt to open non-existant time data files
-    psLibInit("test.psTime.config1");
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeInit4(void)
-{
-    // Test D - Attempt to read incorrect number of files
-    psLibInit("test.psTime.config2");
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeInit5(void)
-{
-    // Test E - Attempt to read incorrect number of from values
-    psLibInit("test.psTime.config3");
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimeInit6(void)
-{
-    // Test F - Attempt to read data file with typo in number
-    psLibInit("test.psTime.config4");
-    psLibFinalize();
-
-    return 0;
-}
-
-psS32 testTimer1(void)
-{
-    psF64 testTime = 0.0;
-    psF64 testTime2 = 0.0;
-    psF64 testTime3 = 0.0;
-
-    if ( !psTimerStart("newTime") ) {
-        printf("TimerStart Failed\n");
-        return 1;
-    }
-    testTime = psTimerMark("newTime");
-    if (testTime == 0.0) {
-        printf("TimerMark Failed\n");
-        return 2;
-    }
-    testTime2 = psTimerClear("newTime");
-    if (testTime2 == 0.0) {
-        printf("TimerClear Failed\n");
-        return 3;
-    }
-    psTimerStart("newTime");
-    testTime3 = psTimerStop();
-    if (testTime3 == 0.0) {
-        printf("TimerStop Failed\n");
-        return 4;
-    }
-    return 0;
-}
-
-psS32 testTideUT1Corr(void)
-{
-    psTime *empty = NULL;
-    psTime *tide = NULL;
-    psTime *noTide = psTimeAlloc(PS_TIME_UTC);
-    noTide->sec = 1049160600;
-    noTide->nsec = 0;
-    noTide->leapsecond = false;
-
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
-    empty = psTime_TideUT1Corr(tide);
-    if (empty != NULL) {
-        psError(PS_ERR_BAD_PARAMETER_NULL, false,
-                "psTime_TideUT1Corr failed to return NULL for NULL input time.\n");
-        return 1;
-    }
-
-    empty = psTime_TideUT1Corr(noTide);
-    if (empty->sec != 1049160599 || empty->nsec != 656981971) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "psTime_TideUT1Corr failed to return correct values.\n");
-        printf("\nsec = %ld, nsec = %u\n", (long int)empty->sec, empty->nsec);
-        return 2;
-    }
-
-    if (!p_psTimeFinalize()) {
-        return 3;
-    }
-
-    psFree(empty);
-    psFree(noTide);
-
-    return 0;
-}
-
Index: anches/czw_branch/20101203/psLib/test/db/tst_psDB.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/db/tst_psDB.c	(revision 30117)
+++ 	(revision )
@@ -1,2224 +1,0 @@
-/** @file  tst_psDB.c
- *
- * -*- mode: C; c-basic-indent: 4; tab-width: 8; indent-tabs-mode: nil -*-
- * vim: set cindent ts=8 sw=4 expandtab:
- *
- *  @brief Contains the tests for psDB.[ch]
- *
- *
- *  @author Aaron Culliney, MHPCC
- *
- *  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-20 01:13:11 $
- *
- *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
- *
- */
-
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "psTest.h"
-#include "pslib_strict.h"
-
-#define STR_1 "hello world!"
-#define STR_2 "foobar"
-#define S32_1 1974
-#define S32_2 -18
-#define F32_1 3.14159
-#define F32_2 3.33
-#define F64_1 2.7182818
-#define F64_2 1.23456789
-#define B_1 TRUE
-#define B_2 FALSE
-
-#define ERROR_TOL   0.001
-
-#define CONST_ROW_1_STR      "randrow1"
-#define CONST_ROW_1_S32      12345
-#define CONST_ROW_1_F32      9876.5
-#define CONST_ROW_1_F64      456.75
-#define CONST_ROW_1_BOOL     TRUE
-
-#define CONST_ROW_2_STR      "randrow2"
-#define CONST_ROW_2_S32      2345
-#define CONST_ROW_2_F32      876.5
-#define CONST_ROW_2_F64      56.75
-#define CONST_ROW_2_BOOL     FALSE
-
-#define TAB_COL_0_NAME      "key_string"
-#define TAB_COL_1_NAME      "key_s32"
-#define TAB_COL_2_NAME      "key_f32"
-#define TAB_COL_3_NAME      "key_f64"
-#define TAB_COL_4_NAME      "key_bool"
-#define TAB_COL_5_NAME      "key_s32_0"
-
-static psDB *_init_psDB( void );
-static psMetadata *_get_CreateTableMetadata( void );
-static psMetadata *_get_RowMetadataValues(const char *val0, psS32 val1, psF32 val2, psF64 val3, psBool val4);
-static psMetadata *_get_RowMetadata(
-    const char *key0, const char *comm0, const char *val0,
-    const char *key1, const char *comm1, psS32  val1,
-    const char *key2, const char *comm2, psF32  val2,
-    const char *key3, const char *comm3, psF64  val3,
-    const char *key4, const char *comm4, psBool val4,
-    const char *key5, const char *comm5, psS32  val5);
-static psMetadata *_get_row( void );
-static psMetadata *_get_invalid_row( void );
-static psMetadata *_get_where( void );
-static psMetadata *_get_invalid_where( void );
-static psMetadata *_get_where_bad_value( void );
-static psMetadata *_get_update_values(const char *val0, psS32 val1, psF32 val2, psF64 val3, psBool val4);
-static bool _check_row(psMetadata* row);
-static bool _check_row_update(psMetadata* row);
-static bool _check_const_row1(psMetadata* row);
-static bool _check_const_row2(psMetadata* row);
-
-//static psS32 TPDBCreate( void );
-//static psS32 TPDBDrop( void );
-static psS32 TPDBInit( void );
-static psS32 TPDBChange( void );
-static psS32 TPDBCreateTable( void );
-static psS32 TPDBDropTable( void );
-static psS32 TPDBSelectColumn( void );
-static psS32 TPDBSelectColumnNum( void );
-static psS32 TPDBSelectRows( void );
-static psS32 TPDBInsertOneRow( void );
-static psS32 TPDBInsertRows( void );
-static psS32 TPDBDumpRows( void );
-static psS32 TPDBDumpCols( void );
-static psS32 TPDBUpdateRows( void );
-static psS32 TPDBDeleteRows( void );
-
-testDescription tests[] = {
-                              {TPDBInit,           841,  "dbInit",            0, false},
-                              {TPDBChange,         842,  "dbChange",          0, false},
-                              {TPDBCreateTable,    843,  "dbCreateTable",     0, false},
-                              {TPDBDropTable,      844,  "dbDropTable",       0, false},
-                              {TPDBSelectColumn,   845,  "dbSelectColumn",    0, false},
-                              {TPDBSelectColumnNum,846,  "dbSelectColumnNum", 0, false},
-                              {TPDBSelectRows,     847,  "dbSelectRows",      0, false},
-                              {TPDBInsertOneRow,   848,  "dbInsertOneRow",    0, false},
-                              {TPDBInsertRows,     849,  "dbInsertRows",      0, false},
-                              {TPDBDumpRows,       850,  "dbDumpRows",        0, false},
-                              {TPDBDumpCols,       851,  "dbDumpCols",        0, false},
-                              {TPDBUpdateRows,     852,  "dbUpdateRows",      0, false},
-                              {TPDBDeleteRows,     853,  "dbDeleteRows",      0, false},
-                              //{TPDBCreate,        -14, "dbCreate",          0, false},
-                              //{TPDBDrop,          -15, "dbDrop",            0, false},
-                              {NULL}
-                          };
-
-static const char *host    = "localhost";
-static const char *user    = "test";
-static const char *passwd  = "";
-static const char *dbname  = "test";
-
-// internal method to initialize DB
-psDB *_init_psDB( void )
-{
-    psDB *dbh = NULL;
-
-    // Initialize database connection with test database
-    dbh = psDBInit(host, user, passwd, dbname);
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not initialize DB connection in %s!", __func__ );
-    }
-
-    return dbh;
-}
-
-psMetadata *_get_CreateTableMetadata( void )
-{
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string",     "90000", // value used to determine size of field
-               TAB_COL_1_NAME,    "Primary Key",        0,       // values unused here ...
-               TAB_COL_2_NAME,    "Key",                0.0,
-               TAB_COL_3_NAME,    "",                   0.0,
-               TAB_COL_4_NAME,   "",                   FALSE,
-               TAB_COL_5_NAME,  "Key,AUTO_INCREMENT", 0);
-}
-
-psMetadata *_get_RowMetadataValues(const char *val0, psS32 val1, psF32 val2, psF64 val3, psBool val4)
-{
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string", val0,
-               TAB_COL_1_NAME,    "comment-s32",    val1,
-               TAB_COL_2_NAME,    "comment-f32",    val2,
-               TAB_COL_3_NAME,    "comment-f64",    val3,
-               TAB_COL_4_NAME,   "comment-bool",   val4,
-               NULL,         NULL,             0.0);
-}
-
-psMetadata *_get_RowMetadata(
-    const char *key0, const char *comm0, const char *val0,
-    const char *key1, const char *comm1, psS32  val1,
-    const char *key2, const char *comm2, psF32  val2,
-    const char *key3, const char *comm3, psF64  val3,
-    const char *key4, const char *comm4, psBool val4,
-    const char *key5, const char *comm5, psS32  val5)
-{
-    psMetadata *md = NULL;
-    psMetadataItem *str=NULL, *s32_0=NULL, *s32=NULL, *f32=NULL, *f64=NULL, *b;
-
-    md = psMetadataAlloc();
-    if (md == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadata in %s!", __func__ );
-        return NULL;
-    }
-    if (key0 != NULL) {
-        str = psMetadataItemAllocStr(key0, comm0, val0);
-    }
-    if (key5 != NULL) {
-        s32_0 = psMetadataItemAllocS32(key5, comm5, val5);
-    }
-    s32 = psMetadataItemAllocS32 (key1, comm1, val1);
-    f32 = psMetadataItemAllocF32 (key2, comm2, val2);
-    f64 = psMetadataItemAllocF64 (key3, comm3, val3);
-    b   = psMetadataItemAllocBool(key4, comm4, val4);
-
-    if ( ((key0 != NULL) && (str == NULL)) || (s32 == NULL) || (f32 == NULL) || (f64 == NULL) || (b == NULL) ||
-            ((key5 != NULL) && (s32_0 == NULL)) ) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadataItem(s) in %s!", __func__ );
-        return NULL;
-    }
-    if ( ((key0 != NULL) && !psMetadataAddItem(md, str, 0, 0)) ||
-            !psMetadataAddItem(md, s32, 0, 0) || !psMetadataAddItem(md, f32, 0, 0) ||
-            !psMetadataAddItem(md, f64, 0, 0) || !psMetadataAddItem(md, b,   0, 0) ||
-            ((key5 != NULL) && !psMetadataAddItem(md, s32_0, 0, 0))) {
-        psError(PS_ERR_UNKNOWN, true, "could not add psMetadataItem(s) to psMetadata in %s!", __func__ );
-        return NULL;
-    }
-
-    if (str != NULL) {
-        psFree(str);
-    }
-    psFree(s32);
-    psFree(f32);
-    psFree(f64);
-    psFree(b);
-    if (s32_0 != NULL) {
-        psFree(s32_0);
-    }
-
-    return md;
-}
-
-psMetadata *_get_const_row1( void )
-{
-    char buf[32];
-    snprintf(buf, 32, "%s", CONST_ROW_1_STR );
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string", buf,
-               TAB_COL_1_NAME,    "comment-s32",    CONST_ROW_1_S32,
-               TAB_COL_2_NAME,    "comment-f32",    CONST_ROW_1_F32,
-               TAB_COL_3_NAME,    "comment-f64",    CONST_ROW_1_F64,
-               TAB_COL_4_NAME,   "comment-bool",   CONST_ROW_1_BOOL,
-               NULL,         NULL,             0.0);
-}
-
-psMetadata *_get_const_row2( void )
-{
-    char buf[32];
-    snprintf(buf, 32, "%s",CONST_ROW_2_STR);
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string", buf,
-               TAB_COL_1_NAME,    "comment-s32",    CONST_ROW_2_S32,
-               TAB_COL_2_NAME,    "comment-f32",    CONST_ROW_2_F32,
-               TAB_COL_3_NAME,    "comment-f64",    CONST_ROW_2_F64,
-               TAB_COL_4_NAME,   "comment-bool",   CONST_ROW_2_BOOL,
-               NULL,         NULL,             0.0);
-}
-
-psMetadata *_get_row( void )
-{
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string", STR_1,
-               TAB_COL_1_NAME,    "comment-s32",    S32_1,
-               TAB_COL_2_NAME,    "comment-f32",    F32_1,
-               TAB_COL_3_NAME,    "comment-f64",    F64_1,
-               TAB_COL_4_NAME,   "comment-bool",   B_1,
-               NULL,         NULL,             0.0);
-}
-
-psMetadata *_get_invalid_row( void )
-{
-    return _get_RowMetadata(
-               TAB_COL_0_NAME, "comment-string", STR_1,
-               TAB_COL_1_NAME,    "comment-s32",    S32_1,
-               "key_999",    "comment-f32",    F32_1,
-               TAB_COL_3_NAME,    "comment-f64",    F64_1,
-               TAB_COL_4_NAME,   "comment-bool",   B_1,
-               NULL,         NULL,             0.0);
-}
-
-psMetadata *_get_where( void )
-{
-    psMetadata *md = NULL;
-    psMetadataItem *s32=NULL;
-
-    md = psMetadataAlloc();
-    if (md == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadata in %s!", __func__ );
-        return NULL;
-    }
-    s32 = psMetadataItemAllocS32(TAB_COL_1_NAME, "", S32_1);
-    if (s32 == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadataItem in %s!", __func__ );
-        return NULL;
-    }
-    if (!psMetadataAddItem(md, s32, 0, 0)) {
-        psError(PS_ERR_UNKNOWN, true, "could not add psMetadataItem(s) to psMetadata in %s!", __func__ );
-        return NULL;
-    }
-
-    psFree(s32);
-    return md;
-}
-
-psMetadata *_get_invalid_where( void )
-{
-    psMetadata *md = NULL;
-    psMetadataItem *s32=NULL;
-
-    md = psMetadataAlloc();
-    if (md == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadata in %s!", __func__ );
-        return NULL;
-    }
-    s32 = psMetadataItemAllocS32("col999", "", S32_1);
-    if (s32 == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadataItem in %s!", __func__ );
-        return NULL;
-    }
-    if (!psMetadataAddItem(md, s32, 0, 0)) {
-        psError(PS_ERR_UNKNOWN, true, "could not add psMetadataItem(s) to psMetadata in %s!", __func__ );
-        return NULL;
-    }
-
-    psFree(s32);
-    return md;
-}
-
-psMetadata *_get_where_bad_value( void )
-{
-    psMetadata *md = NULL;
-    psMetadataItem *s32=NULL;
-
-    md = psMetadataAlloc();
-    if (md == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadata in %s!", __func__ );
-        return NULL;
-    }
-    s32 = psMetadataItemAllocS32(TAB_COL_1_NAME, "", S32_1 + 1);
-    if (s32 == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "could not create psMetadataItem in %s!", __func__ );
-        return NULL;
-    }
-    if (!psMetadataAddItem(md, s32, 0, 0)) {
-        psError(PS_ERR_UNKNOWN, true, "could not add psMetadataItem(s) to psMetadata in %s!", __func__ );
-        return NULL;
-    }
-
-    psFree(s32);
-    return md;
-}
-
-psMetadata *_get_update_values(const char *val0, psS32 val1, psF32 val2, psF64 val3, psBool val4)
-{
-    return _get_RowMetadataValues(val0, val1, val2, val3, val4);
-}
-
-bool _check_row(psMetadata* row)
-{
-    bool              returnValue = true;
-    psMetadataItem*   item        = NULL;
-
-    item = psMetadataLookup(row,TAB_COL_0_NAME);
-    if((item==NULL) || (strcmp(item->data.V,STR_1)!=0)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_string item %s not as expected %s",
-                item->data.V,STR_1);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_1_NAME);
-    if((item==NULL) || (item->data.S32 != S32_1)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_s32 item %d not as expected %d",
-                item->data.S32, S32_1);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_2_NAME);
-    if((item==NULL) || (fabs(item->data.F32-F32_1)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f32 item %f not as expected %f",
-                item->data.F32, F32_1);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_3_NAME);
-    if((item==NULL) || (fabs(item->data.F64-F64_1)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f64 item %lf not as expected %lf",
-                item->data.F64,F64_1);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_4_NAME);
-    if((item==NULL) || (item->data.B != B_1)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_bool item %d not as expected %d",
-                item->data.B, B_1);
-        return false;
-    }
-
-    return returnValue;
-}
-
-bool _check_row_update(psMetadata* row)
-{
-    bool              returnValue = true;
-    psMetadataItem*   item        = NULL;
-
-    item = psMetadataLookup(row,TAB_COL_0_NAME);
-    if((item==NULL) || (strcmp(item->data.V,STR_2)!=0)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_string item %s not as expected %s",
-                item->data.V,STR_2);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_1_NAME);
-    if((item==NULL) || (item->data.S32 != S32_2)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_s32 item %d not as expected %d",
-                item->data.S32, S32_2);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_2_NAME);
-    if((item==NULL) || (fabs(item->data.F32-F32_2)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f32 item %f not as expected %f",
-                item->data.F32, F32_2);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_3_NAME);
-    if((item==NULL) || (fabs(item->data.F64-F64_2)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f64 item %lf not as expected %lf",
-                item->data.F64,F64_2);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_4_NAME);
-    if((item==NULL) || (item->data.B != B_2)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_bool item %d not as expected %d",
-                item->data.B, B_2);
-        return false;
-    }
-
-    return returnValue;
-}
-
-bool _check_const_row1(psMetadata* row)
-{
-    bool              returnValue = true;
-    psMetadataItem*   item        = NULL;
-
-    item = psMetadataLookup(row,TAB_COL_0_NAME);
-    if((item==NULL) || (strcmp(item->data.V,CONST_ROW_1_STR)!=0)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_string item %s not as expected %s",
-                item->data.V,CONST_ROW_1_STR);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_1_NAME);
-    if((item==NULL) || (item->data.S32 != CONST_ROW_1_S32)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_s32 item %d not as expected %d",
-                item->data.S32, CONST_ROW_1_S32);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_2_NAME);
-    if((item==NULL) || (fabs(item->data.F32-CONST_ROW_1_F32)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f32 item %f not as expected %f",
-                item->data.F32, CONST_ROW_1_F32);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_3_NAME);
-    if((item==NULL) || (fabs(item->data.F64-CONST_ROW_1_F64)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f64 item %lf not as expected %lf",
-                item->data.F64,CONST_ROW_1_F64);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_4_NAME);
-    if((item==NULL) || (item->data.B != CONST_ROW_1_BOOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_bool item %d not as expected %d",
-                item->data.B, CONST_ROW_1_BOOL);
-        return false;
-    }
-
-    return returnValue;
-}
-
-bool _check_const_row2(psMetadata* row)
-{
-    bool              returnValue = true;
-    psMetadataItem*   item        = NULL;
-
-    item = psMetadataLookup(row,TAB_COL_0_NAME);
-    if((item==NULL) || (strcmp(item->data.V,CONST_ROW_2_STR)!=0)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_string item %s not as expected %s",
-                item->data.V,CONST_ROW_2_STR);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_1_NAME);
-    if((item==NULL) || (item->data.S32 != CONST_ROW_2_S32)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_s32 item %d not as expected %d",
-                item->data.S32, CONST_ROW_2_S32);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_2_NAME);
-    if((item==NULL) || (fabs(item->data.F32-CONST_ROW_2_F32)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f32 item %f not as expected %f",
-                item->data.F32, CONST_ROW_2_F32);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_3_NAME);
-    if((item==NULL) || (fabs(item->data.F64-CONST_ROW_2_F64)>ERROR_TOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_f64 item %lf not as expected %lf",
-                item->data.F64,CONST_ROW_2_F64);
-        return false;
-    }
-
-    item = psMetadataLookup(row,TAB_COL_4_NAME);
-    if((item==NULL) || (item->data.B != CONST_ROW_2_BOOL)) {
-        psError(PS_ERR_UNKNOWN,true,"Column key_bool item %d not as expected %d",
-                item->data.B, CONST_ROW_2_BOOL);
-        return false;
-    }
-
-    return returnValue;
-}
-
-psS32 main(psS32 argc, char* argv[])
-{
-    psLogSetLevel( PS_LOG_INFO );
-
-    srand(time(NULL));
-
-    return ( ! runTestSuite( stderr, "psDB", tests, argc, argv ) );
-}
-
-// Testpoint #841, initialize/break-down MySQL connection.
-psS32 TPDBInit( void )
-{
-    psDB *dbh = NULL;
-
-    // Initialize database with valid arguments
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL to be returned for valid arguments");
-        return 1;
-    }
-
-    // Cleanup database/connection with valid psDB object
-    psDBCleanup(dbh);
-
-    // Attempt to initialize database with invalid arguments
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid host");
-    dbh = psDBInit("xxx",NULL,NULL,NULL);
-    if(dbh != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL psDB with invalid arguments");
-        return 2;
-    }
-
-    // Attempt cleanup database/connection with NULL psDB object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL database objec");
-    psDBCleanup(NULL);
-
-    return 0;
-}
-
-// Testpoint #842, psDBChange shall change databases.
-psS32 TPDBChange( void )
-{
-    psDB *dbh = NULL;
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL for valid arguments");
-        return 1;
-    }
-
-    // Attempt to change database with valid arguments
-    if(!psDBChange(dbh, dbname)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for valid arguments");
-        return 2;
-    }
-
-    // Attemp to change database to invalid database name
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid database");
-    if(psDBChange(dbh,"abc")) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return true for unknown database name");
-        return 3;
-    }
-
-    // Cleanup database connection
-    psDBCleanup(dbh);
-
-    // Attempt to change database with NULL database object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for null database object");
-    if(psDBChange(NULL,dbname)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return true for NULL database object");
-        return 4;
-    }
-
-    return 0;
-}
-
-// Testpoint #843, psDBCreateTable shall create tables in the test database ...
-psS32 TPDBCreateTable( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table1";
-
-    // Create metadata for table definition
-    psMetadata *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL for valid argument in database connection");
-        return 1;
-    }
-
-    // Attempt to create database table with valid arguments
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false for valid arguments");
-        return 2;
-    } else {
-        // Drop the table from the test database
-        psDBDropTable(dbh, table);
-    }
-
-    // Free metadata definition of table
-    psFree(md);
-
-    // Attempt to create table with NULL table definition
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL parameter");
-    if(psDBCreateTable(dbh,table,NULL)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of true for NULL metadata object");
-        return 3;
-    }
-
-    // Attempt to create table with NULL connection
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL parameter");
-    if(psDBCreateTable(NULL, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of true for NULL database object");
-        return 4;
-    }
-
-    // Close/cleanup database connection
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #844, psDBDropTable shall remove tables in the test database ...
-psS32 TPDBDropTable( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table2";
-
-    // Create table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return to initialize database");
-        return 1;
-    }
-
-    // Create table in database
-    if(psDBCreateTable(dbh, table, md)) {
-
-        // Drop table with valid arguments
-        if(!psDBDropTable(dbh, table)) {
-            psError(PS_ERR_UNKNOWN,true,"Did not expect return false for valid arguments");
-            return 2;
-        }
-
-        // insert should fail since the table has been drop from database
-        psLogMsg( __func__, PS_LOG_INFO, "psDBDropTable: insert should fail here...\n" );
-        row = _get_row();
-        if (psDBInsertOneRow(dbh, table, row)) {
-            psError(PS_ERR_UNKNOWN,true,"Did not expect to successfully insert row into dropped table");
-            return 3;
-        }
-        psFree(row);
-    } else {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false to create table");
-        return 4;
-    }
-
-    // Attempt to drop table from NULL psDB object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL database object");
-    if(psDBDropTable(NULL,table)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return false as expected for NULL database object");
-        return 5;
-    }
-
-    // Attempt to drop table from valid psDB but invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid table");
-    if(psDBDropTable(dbh,"table99")) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return false as expected for invalid table");
-        return 6;
-    }
-
-    // Attempt to drop table from valid psDB but NULL table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL table");
-    if(psDBDropTable(dbh,NULL)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not return false as expected for NULL table");
-        return 7;
-    }
-
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #845, TPDBSelectColumn shall write/select a column from a test table ...
-psS32 TPDBSelectColumn( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table3";
-    psArray *ary = NULL;
-    char *ptr=NULL;
-
-    // Create table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL to initialize database connection");
-        return 1;
-    }
-
-    // Create database table
-    if(!psDBCreateTable(dbh,table,md)) {
-        psError(PS_ERR_UNKNOWN,true,"Unable to create database table for testing");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Insert known constant row #1
-    row = _get_const_row1();
-    if(!psDBInsertOneRow(dbh, table, row)) {
-        psError(PS_ERR_UNKNOWN,true,"Unable to add rows to test database");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-    psFree(row);
-
-    // Insert known constant row #2
-    row = _get_const_row2();
-    if(!psDBInsertOneRow(dbh, table, row)) {
-        psError(PS_ERR_UNKNOWN,true,"Unable to add rows to test database");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-    psFree(row);
-
-    // Insert known row
-    row = _get_row();
-    if(!psDBInsertOneRow(dbh, table, row)) {
-        psError(PS_ERR_UNKNOWN,true,"Unable to add rows to test database");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    psFree(row);
-
-    // Select all items in column key_string with valid arguments
-    ary = psDBSelectColumn(dbh, table, TAB_COL_0_NAME, 0);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value of NULL");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-
-    // Verify array contents
-    if(ary->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Array number of items %d not equal to expected %d",
-                ary->n, 3);
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 60;
-    }
-    ptr = psArrayGet(ary, 2);
-    if (strcmp(ptr, CONST_ROW_1_STR)) {
-        psError(PS_ERR_UNKNOWN,true,"key_str column entry[%d] = %s not as expected %s",
-                2,CONST_ROW_1_STR,ptr);
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-    //    psFree(ptr);
-    ptr = psArrayGet(ary, 1);
-    if (strcmp(ptr, CONST_ROW_2_STR)) {
-        psError(PS_ERR_UNKNOWN,true,"key_str column entry[%d] = %s not as expected %s",
-                1,CONST_ROW_2_STR,ptr);
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-    //    psFree(ptr);
-    ptr = psArrayGet(ary, 0);
-    if (strcmp(ptr, STR_1)) {
-        psError(PS_ERR_UNKNOWN,true,"key_str column entry[%d] = %s not as expected %s",
-                0,STR_1,ptr);
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-    //    psFree(ptr);
-    psFree(ary);
-
-    // Select items in column key_bool with limit 10 and valid arguments
-    ary = psDBSelectColumn(dbh, table, TAB_COL_4_NAME, 10);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value of NULL");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-
-    // Verify array contents
-    if(ary->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Array number of items %d not equal to expected %d",
-                ary->n, 3);
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 100;
-    }
-    ptr = psArrayGet(ary, 2);
-    if(atoi(ptr) != CONST_ROW_1_BOOL) {
-        psError(PS_ERR_UNKNOWN,true,"key_bool column entry[%d] = %d not as expected %d",
-                2,CONST_ROW_1_BOOL,atoi(ptr));
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 11;
-    }
-    //    psFree(ptr);
-    ptr = psArrayGet(ary, 1);
-    if(atoi(ptr) != CONST_ROW_2_BOOL) {
-        psError(PS_ERR_UNKNOWN,true,"key_bool column entry[%d] = %d not as expected %d",
-                1,CONST_ROW_2_BOOL,atoi(ptr));
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 12;
-    }
-    //    psFree(ptr);
-    ptr = psArrayGet(ary, 0);
-    if(atoi(ptr) != B_1) {
-        psError(PS_ERR_UNKNOWN,true,"key_bool column entry[%d] = %d not as expected %d",
-                0,B_1,atoi(ptr));
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 13;
-    }
-    //    psFree(ptr);
-    psFree(ary);
-
-    // Attempt to select columns from NULL database object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL database");
-    if(psDBSelectColumn(NULL,table,"key_str",10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for selecting from NULL database");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 14;
-    }
-
-    // Attempt to select column from NULL table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL table");
-    if(psDBSelectColumn(dbh,NULL,"key_str",10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for NULL table");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 15;
-    }
-
-    // Attempt to select column from invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid table");
-    if(psDBSelectColumn(dbh,"table99","key_str",10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for invalid table");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 16;
-    }
-
-    // Attempt to select invalid column from valid database object and valid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid column");
-    if(psDBSelectColumn(dbh,table,"key_null",10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for invalid column");
-        psDBDropTable(dbh, table);
-        psDBCleanup(dbh);
-        return 17;
-    }
-
-    // Clean up table and memory
-    psDBDropTable(dbh, table);
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #846, TPDBSelectColumnNum shall write/select a column from a test table ...
-psS32 TPDBSelectColumnNum( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table4";
-    psVector *vec = NULL;
-
-    // Create table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expected NULL return to initialize database");
-        return 1;
-    }
-
-    // Create database table for test
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for create table");
-        return 2;
-    }
-
-    // Initialize database table with known rows
-    row = _get_const_row1();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_row();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    // Use valid arguments to select column with numeric values to return vector
-    vec = psDBSelectColumnNum(dbh, table, TAB_COL_1_NAME, PS_TYPE_S32, 0);
-
-    // Verify vector returned
-    if (vec == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return with valid arguments");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-    // Verify vector values
-    if(vec->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return vector size not equal to 3");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 30;
-    }
-    if(vec->type.type != PS_TYPE_S32) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return vector type not equal to PS_TYPE_S32");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 31;
-    }
-    if ((vec->data.S32)[0] != S32_1) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                0,vec->data.S32[0], S32_1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-    if ((vec->data.S32)[1] != CONST_ROW_2_S32) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                1,vec->data.S32[1], CONST_ROW_2_S32);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    if ((vec->data.S32)[2] != CONST_ROW_1_S32) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                2,vec->data.S32[2], CONST_ROW_1_S32);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    psFree(vec);
-
-    // Use valid arguments to select column with numeric values to return vector
-    vec = psDBSelectColumnNum(dbh, table, TAB_COL_4_NAME, PS_TYPE_BOOL, 0);
-
-    // Verify vector returned
-    if (vec == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return with valid arguments");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-    // Verify vector values
-    if(vec->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return vector size not equal to 3");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-    if(vec->type.type != PS_TYPE_BOOL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return vector type not equal to PS_TYPE_BOOL");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-    if ((vec->data.U8)[0] != B_1) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                0,vec->data.U8[0],B_1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-    if ((vec->data.U8)[1] != CONST_ROW_2_BOOL) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                0,vec->data.U8[0],CONST_ROW_2_BOOL);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 11;
-    }
-    if ((vec->data.U8)[2] != CONST_ROW_1_BOOL) {
-        psError(PS_ERR_UNKNOWN,true,"vector value[%d] = %d not as expected %d",
-                0,vec->data.U8[0],CONST_ROW_1_BOOL);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 12;
-    }
-    psFree(vec);
-
-    // Attempt to select columns from NULL database
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error for NULL database object");
-    if(psDBSelectColumnNum(NULL,table,TAB_COL_4_NAME,PS_TYPE_BOOL,10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return with NULL database object");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 13;
-    }
-
-    // Attempt to select columns from NULL table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error for NULL table");
-    if(psDBSelectColumnNum(dbh,NULL,TAB_COL_4_NAME,PS_TYPE_BOOL,10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return with NULL table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 14;
-    }
-
-    // Attempt to select columns from invalid column
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error for invalid column");
-    if(psDBSelectColumnNum(dbh,table,"key_999",PS_TYPE_BOOL,10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return with NULL column");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 15;
-    }
-
-    // Attempt to select columns from invalid column
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error for invalid type");
-    if(psDBSelectColumnNum(dbh,table,TAB_COL_0_NAME,0,10) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return with invalid type");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 16;
-    }
-
-    psDBDropTable(dbh, table);
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #847, TPDBSelectRows shall write/select data from a test table ...
-psS32 TPDBSelectRows( void )
-{
-    int i;
-    psDB *dbh = NULL;
-    const char* table = "table5";
-    psArray *ary=NULL, *ary1=NULL, *ary2=NULL;
-    psMetadataItem *item = NULL;
-
-    // Create database table definition
-    psMetadata *where=NULL, *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expected NULL return to initialize database");
-        return 1;
-    }
-
-    psDBDropTable(dbh,table);
-    // Create database table for test
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for create table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Initialize database table with known rows
-    row = _get_const_row1();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_row();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    // Generate valid where clause
-    where = _get_where();
-
-    // Select rows with non limit
-    ary1 = psDBSelectRows(dbh, table, where, 0);
-
-    // Select rows with a limit
-    ary2 = psDBSelectRows(dbh, table, where, 1);
-    psFree(where);
-
-    // Cycle through both arrays to verify results
-    for (i=0; i<2; i++) {
-        ary = i ? ary2 : ary1;
-
-        // Verify return array not NULL
-        if (ary == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL");
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 1;
-        }
-
-        if(ary->n != 1) {
-            psError(PS_ERR_UNKNOWN,true,"Number of rows %d not as expected %d",
-                    ary->n, 1);
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 2;
-        }
-
-        // Get metadata which contains row from array
-        row = (psMetadata*)psArrayGet(ary, 0);
-
-        // Get key_s32 item from metadata
-        item = psMetadataLookup(row, TAB_COL_1_NAME);
-        if (item == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Could not find key_s32 item in row metadata");
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 2;
-        }
-        if (item->data.S32 != S32_1) {
-            psError(PS_ERR_UNKNOWN,true,"Row item %d not as expected %d",
-                    item->data.S32,S32_1);
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 3;
-        }
-
-        // Get key_bool item from metadata
-        item = psMetadataLookup(row, TAB_COL_4_NAME);
-        if (item == NULL) {
-            psError(PS_ERR_UNKNOWN,true,"Could not find key_bool item in row metadata");
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 2;
-        }
-        if (item->data.B != B_1) {
-            psError(PS_ERR_UNKNOWN,true,"Row item %d not as expected %d",
-                    item->data.S32,S32_1);
-            psDBDropTable(dbh,table);
-            psDBCleanup(dbh);
-            return 4;
-        }
-        psFree(ary);
-        //        psFree(row);
-    }
-
-    // Attempt to select rows with NULL database object
-    psLogMsg(__func__,PS_LOG_INFO,
-             "Following should generate an error message for NULL database object");
-    if(psDBSelectRows(NULL, table, where, 0) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for NULL database object");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-
-    // Attempt to select rows with invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid table");
-    if(psDBSelectRows(dbh, NULL, where, 0) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL return for NULL database object");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-
-    // Select rows with no where specified
-    ary1 = psDBSelectRows(dbh, table, NULL, 0);
-    if(ary1 == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return using NULL where");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    if(ary1->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Rows return %d not as expected %d",
-                ary->n,3);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-    psFree(ary1);
-
-    psDBDropTable(dbh, table);
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #848, TPDBInsertOneRow shall write a row of data into a test table ...
-psS32 TPDBInsertOneRow( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table6";
-    psMetadata *invalidRow = NULL;
-    psArray*    ary = NULL;
-
-    // Create table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL for database initialization");
-        return 1;
-    }
-
-    // Create database table
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for create database");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Insert a single row with valid arguments
-    row = _get_const_row1();
-    if(!psDBInsertOneRow(dbh, table, row)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for inserting row w/ valid arguments");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-    // Verify row was added to table
-    ary = psDBSelectRows(dbh,table,NULL,0);
-    if(ary->n != 1) {
-        psError(PS_ERR_UNKNOWN,true,"Number of rows %d not as expected %d",
-                ary->n,1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 30;
-    }
-    psFree(ary);
-
-    // Insert a single row with NULL database
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL database");
-    if(psDBInsertOneRow(NULL,table,row)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value true for NULL database");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-
-    // Insert a single row which has column which does not match table
-    invalidRow = _get_invalid_row();
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid column item");
-    if(psDBInsertOneRow(dbh,table,invalidRow)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value true for invalid column item");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-
-    // Insert a single row with invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid table");
-    if(psDBInsertOneRow(dbh,"table999",row)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value true for invalid table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-
-    // Insert a single row with NULL row
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL row");
-    if(psDBInsertOneRow(dbh,table,NULL)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value true for NULL row");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-
-    psFree(row);
-    psFree(invalidRow);
-    psDBDropTable(dbh, table);
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #849, TPDBInsertRows shall write rows of data into a test table ...
-psS32 TPDBInsertRows( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table7";
-    psArray *rowSet = NULL;
-    psArray* dumpRowSet = NULL;
-    psMetadataItem *item=NULL;
-    psArray* ary = NULL;
-    psMetadata* invalidRow = NULL;
-    psArray* invalidRowSet = NULL;
-
-    //Create database table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL for initializing database connection");
-        return 1;
-    }
-
-    // Create database table for testing
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for creating table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Create array of row elements
-    rowSet = psArrayAlloc(3);
-    rowSet->n = 0;
-
-    row = _get_const_row1();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    row = _get_row();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    // Insert rows with valid arguments
-    if(!psDBInsertRows(dbh, table, rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for inserting rows w/ valid args");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-
-    // Verify row was added to table
-    ary = psDBSelectRows(dbh,table,NULL,0);
-    if(ary->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Number of rows %d not as expected %d",
-                ary->n,3);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 30;
-    }
-    psFree(ary);
-
-    // extra checks ...
-    dumpRowSet = psDBDumpRows(dbh, table);
-    if (dumpRowSet == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL from dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-
-    // Get first row from array
-    row = (psMetadata*)psArrayGet(dumpRowSet, 0);
-    // Verify contents for column key_s32
-    item = psMetadataLookup(row, TAB_COL_1_NAME);
-    if ((item == NULL) || (item->data.S32 != S32_1)) {
-        psError(PS_ERR_UNKNOWN,true,"Column value %d not as expected %d",
-                item->data.S32, S32_1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    // Verify contents for column key_bool
-    item = psMetadataLookup(row, TAB_COL_4_NAME);
-    if ((item == NULL) || (item->data.B != B_1)) {
-        psError(PS_ERR_UNKNOWN,true,"Column value %d not as expected %d",
-                item->data.B, B_1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    psFree(dumpRowSet);
-    //    psFree(row);
-
-    // Insert rows with NULL database object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL database");
-    if(psDBInsertRows(NULL,table,rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false for NULL database");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-
-    // Insert rows with NULL table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL table");
-    if(psDBInsertRows(dbh,NULL,rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false for NULL table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 70;
-    }
-
-    // Insert rows with invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid table");
-    if(psDBInsertRows(dbh,"table999",rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false for invalid table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-
-    // Insert rows with NULL array of rows to be inserted
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL row array");
-    if(psDBInsertRows(dbh,table,NULL)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false for NULL row array");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-
-    // Insert a single row which has column which does not match table
-    invalidRow = _get_invalid_row();
-    // Create array of invalid row element
-    invalidRowSet = psArrayAlloc(1);
-    invalidRowSet->n = 0;
-    psArrayAdd(invalidRowSet, 0, invalidRow);
-    psFree(invalidRow);
-
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid column item");
-    if(psDBInsertRows(dbh,table,invalidRowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value true for invalid column item");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-    psFree(invalidRowSet);
-
-    psFree(rowSet);
-    psDBDropTable(dbh, table);
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #850, TPDBDumpRows shall dump all rows from a test table ...
-psS32 TPDBDumpRows( void )
-{
-    psDB *dbh = NULL;
-    const char* table = "table8";
-    psArray *ary = NULL;
-
-    // Create table definition metadata
-    psMetadata *row=NULL, *md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL from initializing database");
-        return 1;
-    }
-
-    // Create table for testing
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false from creating table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Insert known data rows into table
-    row = _get_const_row1();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_row();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    // Dump row with valid parameters
-    ary = psDBDumpRows(dbh, table);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL for dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-    if(ary->n != 3) {
-        psError(PS_ERR_UNKNOWN,true,"Rows dumped %d not as expected %d",
-                ary->n, 3);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-
-    row = (psMetadata*)psArrayGet(ary, 0);
-    if(!_check_row(row)) {
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    //    psFree(row);
-    row = (psMetadata*)psArrayGet(ary, 1);
-    if(!_check_const_row2(row)) {
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    //    psFree(row);
-    row = (psMetadata*)psArrayGet(ary, 2);
-    if(!_check_const_row1(row)) {
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-    //    psFree(row);
-    psFree(ary);
-
-    // Attempt to dump row with database NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL database");
-    if(psDBDumpRows(NULL,table)!=NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return non-NULL for NULL database specified");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-
-    // Attempt to dump row with table NULL
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL table");
-    if(psDBDumpRows(dbh,NULL)!=NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return non-NULL for NULL table specified");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-
-    psDBDropTable(dbh, table);
-
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #851, TPDBDumpCols shall dump all cols from a test table ...
-psS32 TPDBDumpCols( void )
-{
-    psDB*                dbh     = NULL;
-    const char*          table   = "table9";
-    psMetadata*          row     = NULL;
-    psMetadata*          meta    = NULL;
-    psMetadata*          md      = NULL;
-    psMetadataIterator*  mdIter  = NULL;
-    psMetadataItem*      mdItem  = NULL;
-    int                  itemNum = 0;
-
-    // Create database table definition
-    md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return to initialize database");
-        return 1;
-    }
-
-    // Create database table for testing
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return of false to create test table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Add row with known data values
-    row = _get_const_row1();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    row = _get_row();
-    psDBInsertOneRow(dbh, table, row);
-    psFree(row);
-
-    // Dump columns with valid arguments
-    meta = psDBDumpCols(dbh, table);
-    mdIter = psMetadataIteratorAlloc(meta,PS_LIST_HEAD,NULL);
-
-    // Verify contents of metadata returned
-    if (meta == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return value NULL for dumpCols with valid args");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-    if(meta->list->n != 6) {
-        psError(PS_ERR_UNKNOWN,true,"Number of cols = %d not as expected %d",
-                meta->list->n,6);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-    // Verify the metadata items
-    itemNum = 0;
-    while ((mdItem = psMetadataGetAndIncrement(mdIter)) != NULL) {
-        switch(itemNum) {
-        case 0:
-            if(mdItem->type != PS_DATA_VECTOR) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_VECTOR);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->type.type != PS_TYPE_S32) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector type %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->type.type, PS_TYPE_S32);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 6*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_5_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_5_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-        case 1:
-            if(mdItem->type != PS_DATA_VECTOR) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_VECTOR);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->type.type != PS_TYPE_BOOL) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector type %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->type.type, PS_TYPE_BOOL);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 6*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_4_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_4_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-        case 2:
-            if(mdItem->type != PS_DATA_VECTOR) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_VECTOR);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->type.type != PS_TYPE_F64) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector type %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->type.type, PS_TYPE_F64);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 6*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_3_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_3_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-        case 3:
-            if(mdItem->type != PS_DATA_VECTOR) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_VECTOR);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->type.type != PS_TYPE_F32) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector type %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->type.type, PS_TYPE_F32);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 6*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_2_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_2_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-        case 4:
-            if(mdItem->type != PS_DATA_VECTOR) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_VECTOR);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->type.type != PS_TYPE_S32) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector type %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->type.type, PS_TYPE_S32);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 6*(itemNum+1);
-            }
-            if(((psVector*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psVector*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_1_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_1_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-        case 5:
-            if(mdItem->type != PS_DATA_ARRAY) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d type %d not as expected %d",
-                        itemNum,mdItem->type,PS_DATA_ARRAY);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 5*(itemNum+1);
-            }
-            if(((psArray*)mdItem->data.V)->n != 3) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d vector size %d not as expected %d",
-                        itemNum,((psArray*)mdItem->data.V)->n,3);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 7*(itemNum+1);
-            }
-            if(strcmp(mdItem->name,TAB_COL_0_NAME) != 0) {
-                psError(PS_ERR_UNKNOWN,true,"Column #%d name %s not as expected %s",
-                        itemNum,mdItem->name,TAB_COL_0_NAME);
-                psDBDropTable(dbh,table);
-                psDBCleanup(dbh);
-                return 8*(itemNum+1);
-            }
-            break;
-
-        default:
-            break;
-        }
-        itemNum++;
-    }
-    psFree(mdIter);
-    psFree(meta);
-
-    // Attempt to dump columns from NULL database object
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL database");
-    if(psDBDumpCols(NULL,table) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL when dumping columns from NULL database");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-
-    // Attempt to dump columns for NULL table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL table");
-    if(psDBDumpCols(dbh,NULL) != NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect non-NULL when dumping columns from NULL table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 11;
-    }
-
-
-    psDBDropTable(dbh, table);
-
-    psFree(md);
-
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #852, TPDBUpdateRows shall update rows in a test table ...
-psS32 TPDBUpdateRows( void )
-{
-    psDB*            dbh       = NULL;
-    const char*      table     = "table10";
-    psArray*         ary       = NULL;
-    psArray*         rowSet    = NULL;
-    psMetadata*      row       = NULL;
-    psMetadata*      where     = NULL;
-    psMetadata*      updates   = NULL;
-    psMetadata*      md        = NULL;
-    int              chgRows   = 0;
-
-    // Create database table definition
-    md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL when initializing database");
-        return 1;
-    }
-
-    // Create test table
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false to create test table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Create array to hold rows to be added to test table
-    rowSet = psArrayAlloc(3);
-    rowSet->n = 0;
-
-    row = _get_const_row1();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    row = _get_const_row2();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    row = _get_row();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-
-    // Insert rows into test table
-    if(!psDBInsertRows(dbh, table, rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for inserting rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-
-    // Create where metadata to specify update - only one row
-    where = _get_where();
-
-    // Create update metadata to specify values
-    updates = _get_update_values(STR_2, S32_2, F32_2, F64_2, B_2);
-
-    // Perform database update with valid parameters
-    chgRows = psDBUpdateRows(dbh,table,where,updates);
-    if(chgRows != 1) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return other than 1 for valid arguments");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-    // Verify row contents after update
-    ary = psDBDumpRows(dbh, table);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return from dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    row = (psMetadata*)psArrayGet(ary, 0);
-    if(!_check_row_update(row)) {
-        psError(PS_ERR_UNKNOWN,true,"Update row not verified");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    //    psFree(row);
-    psFree(ary);
-
-    // Attempt to update rows with NULL database
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL database");
-    chgRows = psDBUpdateRows(NULL,table,where,updates);
-    if(chgRows != -1) {
-        psError(PS_ERR_UNKNOWN,true,"Updated rows %ld not as expected %ld",
-                chgRows,-1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-
-    // Attempt to update rows with invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid table");
-    chgRows = psDBUpdateRows(dbh,"table999",where,updates);
-    if(chgRows != -1) {
-        psError(PS_ERR_UNKNOWN,true,"Updated rows %ld not as expected %ld",
-                chgRows,-1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-
-    // Attempt to update rows with NULL updates
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for NULL updates");
-    chgRows = psDBUpdateRows(dbh,table,where,NULL);
-    if(chgRows != -1) {
-        psError(PS_ERR_UNKNOWN,true,"Updated rows %ld not as expected %ld",
-                chgRows,-1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-
-    // Attempt to update rows with invalid where specifying non-existent column
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message for invalid where");
-    psFree(where);
-    where = _get_invalid_where();
-    chgRows = psDBUpdateRows(dbh,table,where,updates);
-    if(chgRows != -1) {
-        psError(PS_ERR_UNKNOWN,true,"Updated rows %ld not as expected %ld",
-                chgRows,-1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-
-    // Attempt to update rows with bad value in where statement
-    psFree(where);
-    where = _get_where_bad_value();
-    chgRows = psDBUpdateRows(dbh,table,where,updates);
-    if(chgRows != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Updated rows %ld not as expected %ld",
-                chgRows,0);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-    // Verify row contents after update - no change
-    ary = psDBDumpRows(dbh, table);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect NULL return from dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 11;
-    }
-    row = (psMetadata*)psArrayGet(ary, 0);
-    if(!_check_row_update(row)) {
-        psError(PS_ERR_UNKNOWN,true,"Update row not verified");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 12;
-    }
-    //    psFree(row);
-    psFree(ary);
-
-    psFree(updates);
-    psFree(where);
-    psFree(rowSet);
-    psDBDropTable(dbh, table);
-
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-// Testpoint #853, TPDBDeleteRows shall update rows in a test table ...
-psS32 TPDBDeleteRows( void )
-{
-    psDB*         dbh       = NULL;
-    const char*   table     = "table11";
-    psArray*      ary       = NULL;
-    psArray*      rowSet    = NULL;
-    psMetadata*   where     = NULL;
-    psMetadata*   row       = NULL;
-    psMetadata*   md        = NULL;
-    int           chgRows   = 0;
-
-    // Create database table definition
-    md = _get_CreateTableMetadata();
-
-    // Initialize database connection
-    dbh = _init_psDB();
-    if (dbh == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL for initialize database");
-        return 1;
-    }
-
-    // Create test table
-    if(!psDBCreateTable(dbh, table, md)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for creating test table");
-        psDBCleanup(dbh);
-        return 2;
-    }
-
-    // Create known data rows to put into test table
-    rowSet = psArrayAlloc(3);
-    rowSet->n = 0;
-    row = _get_const_row1();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-    row = _get_const_row2();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-    row = _get_row();
-    psArrayAdd(rowSet, 0, row);
-    psFree(row);
-    if(!psDBInsertRows(dbh, table, rowSet)) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return false for inserting data into table");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 3;
-    }
-
-    // Create where clause to specify the row to remove
-    where = _get_where();
-
-    // Delete row with valid arguments
-    chgRows = psDBDeleteRows(dbh,table,where,10);
-    if(chgRows != 1) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %ld",
-                chgRows,1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 4;
-    }
-    // Verify table contents
-    ary = psDBDumpRows(dbh, table);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL for dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 5;
-    }
-    if (ary->n != 2) {
-        psError(PS_ERR_UNKNOWN,true,"Remaining rows %d not as expected %d",
-                ary->n,2);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 6;
-    }
-    psFree(ary);
-
-    // Attempt to delete row just deleted again
-    chgRows = psDBDeleteRows(dbh,table,where,10);
-    if(chgRows != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %ld",
-                chgRows,0);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 7;
-    }
-    // Verify table contents
-    ary = psDBDumpRows(dbh, table);
-    if (ary == NULL) {
-        psError(PS_ERR_UNKNOWN,true,"Did not expect return NULL for dump rows");
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 8;
-    }
-    if (ary->n != 2) {
-        psError(PS_ERR_UNKNOWN,true,"Remaining rows %d not as expected %d",
-                ary->n,2);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 9;
-    }
-    psFree(ary);
-
-    // Attempt to delete row with NULL database
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for NULL database");
-    chgRows = psDBDeleteRows(NULL,table,where,10);
-    if(chgRows > 0) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %ld",
-                chgRows, -1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 10;
-    }
-
-    // Attempt to delete row with invalid table
-    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message for invalid table");
-    chgRows = psDBDeleteRows(dbh,"table999",where,10);
-    if(chgRows > 0) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %ld",
-                chgRows, -1);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 11;
-    }
-
-    // Attempt to delete row with NULL where - deletes all rows
-    chgRows = psDBDeleteRows(dbh,table,NULL,10);
-    if(chgRows != 2) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %ld",
-                chgRows, 2);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 12;
-    }
-    // Verify table contents
-    ary = psDBDumpRows(dbh, table);
-    if (ary != NULL && ary->n != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Remaining rows %d not as expected %d",
-                ary->n,0);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 14;
-    }
-    psFree(ary);
-
-    // Attempt to delete row with NULL where - deletes all rows from an empty table
-    chgRows = psDBDeleteRows(dbh,table,NULL,10);
-    if(chgRows != 0) {
-        psError(PS_ERR_UNKNOWN,true,"Deleted rows %ld not as expected %d",
-                chgRows, 0);
-        psDBDropTable(dbh,table);
-        psDBCleanup(dbh);
-        return 15;
-    }
-
-    psFree(where);
-    psFree(rowSet);
-    psDBDropTable(dbh, table);
-
-    psFree(md);
-    psDBCleanup(dbh);
-
-    return 0;
-}
-
-//
-// Tests for psDBCreate and psDBDrop can only be executed if the user
-// has system admin privileges for the SQL server so the tests have been
-// commented out.
-//
-// Testpoint #XXX, psDBCreate shall create a new test database.
-//psS32 TPDBCreate( void )
-//{
-//    const char *test_db = "ps_test_db";
-//    psS32 failed = 0;
-//    psDB *dbh = NULL;
-//
-//    dbh = _init_psDB();
-//    if (dbh == NULL) {
-//        return 1;
-//    }
-//
-//    psLogMsg( __func__, PS_LOG_INFO, "psDBCreate shall create new new test database.\n" );
-//
-//    failed = ! psDBCreate(dbh, test_db);
-//    if (!failed) {
-//        psDBDrop(dbh, test_db);
-//    }
-//
-//    psDBCleanup(dbh);
-//
-//    return failed;
-//}
-
-// Testpoint #XXX, psDBDrop shall create a new test database.
-//psS32 TPDBDrop( void )
-//{
-//    const char *test_db = "ps_test_db";
-//    psS32 failed = 0;
-//    psDB *dbh = NULL;
-//
-//    dbh = _init_psDB();
-//    if (dbh == NULL) {
-//        return 1;
-//    }
-//
-//    psLogMsg( __func__, PS_LOG_INFO, "psDBDrop shall create/drop a new new test database.\n" );
-//
-//    failed = psDBCreate(dbh, test_db);
-//    if (!failed) {
-//        failed = ! psDBDrop(dbh, test_db);
-//    }
-//
-//    psDBCleanup(dbh);
-//
-//    return failed;
-//}
-
Index: /branches/czw_branch/20101203/psLib/test/imageops/Makefile.am
===================================================================
--- /branches/czw_branch/20101203/psLib/test/imageops/Makefile.am	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/test/imageops/Makefile.am	(revision 30118)
@@ -22,4 +22,5 @@
 	tap_psImagePixelExtract \
 	tap_psImageInterpolate2 \
+	tap_psImageInterpolate3 \
 	tap_psImageMap \
 	tap_psImageMapFit \
Index: /branches/czw_branch/20101203/psLib/test/imageops/tap_psImageInterpolate3.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/imageops/tap_psImageInterpolate3.c	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/imageops/tap_psImageInterpolate3.c	(revision 30118)
@@ -0,0 +1,163 @@
+#include <stdio.h>
+#include <pslib.h>
+#include "tap.h"
+#include "pstap.h"
+
+# define NUM_POINTS 32
+# define IMAGE_STDEV 10.0
+# define IMAGE_MEAN  20.0
+
+// Generate a dummy variance image
+psImage *generateVariance(int numCols, int numRows, psElemType type)
+{
+    psImage *image = psImageAlloc(numCols, numRows, type);
+    for (int j = 0; j < numRows; j++) {
+        for (int i = 0; i < numCols; i++) {
+            psImageSet(image, i, j, PS_SQR(IMAGE_STDEV));
+        }
+    }
+    return image;
+}
+
+// Generate a dummy image
+psImage *generateImage(psImage *image, psRandom *rnd, int numCols, int numRows, psElemType type)
+{
+    if (!image) {
+	image = psImageAlloc(numCols, numRows, type);
+    }
+    for (int j = 0; j < numRows; j++) {
+        for (int i = 0; i < numCols; i++) {
+            psImageSet(image, i, j, IMAGE_MEAN + IMAGE_STDEV*psRandomGaussian(rnd));
+        }
+    }
+    return image;
+}
+
+// Check a particular combination of image and interpolation parameters
+// Each has 2 + 2*num tests
+void check(int xSize, int ySize,        // Size of image
+           psElemType type,             // Type for image
+           int num,                     // Number of samples over image
+           char *modeName, // Interpolation mode
+           int xKernel, int yKernel,    // Size of interpolation kernel
+           float tol,                    // Tolerance
+	   psRandom *rnd		 // random seed
+    )
+{
+    double imageVal, varianceVal;
+    psImageInterpolateStatus interpOK;
+    psImage *image = NULL;
+
+    psImageInterpolateMode mode = psImageInterpolateModeFromString(modeName);
+    // psImageMaskType maskVal;
+
+    psMemId id = psMemGetLastId();
+
+    int xCenter = xSize / 2;
+    int yCenter = ySize / 2;
+
+    psVector *pt0 = psVectorAlloc(num, PS_TYPE_F32);
+    psVector *pt1 = psVectorAlloc(num, PS_TYPE_F32);
+    psVector *pt2 = psVectorAlloc(num, PS_TYPE_F32);
+    psVector *pt3 = psVectorAlloc(num, PS_TYPE_F32);
+
+    // generate NUM images with Gaussian random noise, measure the interpolated value at
+    // the specified points, save in vectors
+    for (int i = 0; i < num; i++) {
+	image = generateImage(image, rnd, xSize, ySize, type);
+	
+	psImageInterpolation *interp = psImageInterpolationAlloc(mode, image, NULL, NULL, 0, NAN, NAN, 0, 0, 0.0, 0);
+
+	// point (0) : uninterpolated center of center pixel
+	pt0->data.F32[i] = psImageGet(image, xCenter + 0.5, yCenter + 0.5);
+
+	// point (1) : center of center pixel
+        interpOK = psImageInterpolate(&imageVal, NULL, NULL, xCenter + 0.5, yCenter + 0.5, interp);
+	pt1->data.F32[i] = imageVal;
+
+	// point (2) : edge of center pixel
+        interpOK = psImageInterpolate(&imageVal, NULL, NULL, xCenter + 0.5, yCenter, interp);
+	pt2->data.F32[i] = imageVal;
+
+	// point (3) : corner of center pixel
+        interpOK = psImageInterpolate(&imageVal, NULL, NULL, xCenter, yCenter, interp);
+	pt3->data.F32[i] = imageVal;
+
+	psFree (interp);
+    }
+
+    fprintf (stderr, "results for interpolation mode %s\n", modeName);
+
+    // measure the interpolate variance value at the specified locations
+    {
+	psImage *variance = generateVariance(xSize, ySize, type);
+	psImageInterpolation *interp = psImageInterpolationAlloc(mode, image, variance, NULL, 0, NAN, NAN, 0, 0, 0.0, 0);
+	psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
+
+        // Values from interpolation
+
+	psStatsInit(stats);
+	psVectorStats(stats, pt0, NULL, NULL, 0);
+	fprintf (stderr, "pt 0 (pixel %5.2f,%5.2f) : pred: %6.3f, meas: %6.3f (mean: %6.3f)\n", xCenter + 0.5, yCenter + 0.5, IMAGE_STDEV, stats->sampleStdev, stats->sampleMean);
+
+        interpOK = psImageInterpolate(&imageVal, &varianceVal, NULL, xCenter + 0.5, yCenter + 0.5, interp);
+	psStatsInit(stats);
+	psVectorStats(stats, pt1, NULL, NULL, 0);
+	fprintf (stderr, "pt 1 (pixel %5.2f,%5.2f) : pred: %6.3f, meas: %6.3f (mean: %6.3f)\n", xCenter + 0.5, yCenter + 0.5, sqrt(varianceVal), stats->sampleStdev, stats->sampleMean);
+	
+        interpOK = psImageInterpolate(&imageVal, &varianceVal, NULL, xCenter + 0.5, yCenter, interp);
+	psStatsInit(stats);
+	psVectorStats(stats, pt2, NULL, NULL, 0);
+	fprintf (stderr, "pt 2 (pixel %5.2f,%5.2f) : pred: %6.3f, meas: %6.3f (mean: %6.3f)\n", xCenter + 0.5, yCenter + 0.0, sqrt(varianceVal), stats->sampleStdev, stats->sampleMean);
+	
+        interpOK = psImageInterpolate(&imageVal, &varianceVal, NULL, xCenter, yCenter, interp);
+	psStatsInit(stats);
+	psVectorStats(stats, pt3, NULL, NULL, 0);
+	fprintf (stderr, "pt 3 (pixel %5.2f,%5.2f) : pred: %6.3f, meas: %6.3f (mean: %6.3f)\n", xCenter + 0.0, yCenter + 0.0, sqrt(varianceVal), stats->sampleStdev, stats->sampleMean);
+
+	psFree (stats);
+	psFree (interp);
+	psFree (variance);
+    }
+
+    psFree (image);
+    psFree(pt0);
+    psFree(pt1);
+    psFree(pt2);
+    psFree(pt3);
+
+    ok(!psMemCheckLeaks(id, NULL, NULL, false), "No memory leaks");
+
+    return;
+}
+
+# define NTESTS 1000
+
+int main(int argc, char *argv[])
+{
+    psRandom *rnd = psRandomAllocSpecific(PS_RANDOM_TAUS, 0);
+
+    plan_tests(6);
+
+    check(16, 16, PS_TYPE_F32, NTESTS, "BILINEAR", 2, 2, 1.0e-6, rnd); // 66 tests
+    // check(16, 16, PS_TYPE_F64, NTESTS, "BILINEAR", 2, 2, 1.0e-6); // 66 tests
+
+    check(16, 16, PS_TYPE_F32, NTESTS, "BIQUADRATIC", 3, 3, 1.0e-6, rnd); // 66 tests
+    // check(16, 16, PS_TYPE_F64, NTESTS, "BIQUADRATIC", 3, 3, 1.0e-6); // 66 tests
+
+    check(16, 16, PS_TYPE_F32, NTESTS, "GAUSS", 3, 3, 1.0e-3, rnd); // 66 tests
+    // check(16, 16, PS_TYPE_F64, NTESTS, "GAUSS", 3, 3, 1.0e-3); // 66 tests
+
+    check(16, 16, PS_TYPE_F32, NTESTS, "LANCZOS2", 4, 4, 1.0e-3, rnd); // 66 tests
+    // check(16, 16, PS_TYPE_F64, NTESTS, "LANCZOS2", 4, 4, 1.0e-3); // 66 tests
+
+    check(32, 32, PS_TYPE_F32, NTESTS, "LANCZOS3", 6, 6, 1.0e-3, rnd); // 66 tests
+    // check(32, 32, PS_TYPE_F64, NTESTS, "LANCZOS3", 6, 6, 1.0e-3); // 66 tests
+
+    check(32, 32, PS_TYPE_F32, NTESTS, "LANCZOS4", 8, 8, 1.0e-3, rnd); // 66 tests
+    // check(32, 32, PS_TYPE_F64, NTESTS, "LANCZOS4", 8, 8, 1.0e-3); // 66 tests
+
+    psFree (rnd);
+    return exit_status();
+}
+
Index: /branches/czw_branch/20101203/psLib/test/math/data/yraw_01.dat
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/data/yraw_01.dat	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/math/data/yraw_01.dat	(revision 30118)
@@ -0,0 +1,1000 @@
+ 11
+ 16
+ 13
+ 17
+ 17
+ 17
+ 23
+ 14
+ 18
+ 15
+ 16
+ 13
+ 12
+ 17
+ 19
+ 15
+ 21
+ 18
+ 18
+ 17
+ 15
+ 20
+ 26
+ 14
+ 12
+ 13
+ 19
+ 16
+ 14
+ 21
+ 16
+ 12
+ 18
+ 14
+ 18
+ 25
+ 20
+ 16
+ 19
+ 16
+ 14
+ 12
+ 20
+ 13
+ 12
+ 21
+ 16
+ 18
+ 11
+ 22
+ 16
+ 23
+ 20
+ 21
+ 54
+ 12
+ 12
+ 16
+ 17
+ 14
+ 18
+ 21
+ 19
+ 18
+ 16
+ 19
+ 18
+ 23
+ 21
+ 20
+ 20
+ 22
+ 15
+ 13
+ 14
+ 15
+ 19
+ 16
+ 15
+ 23
+ 14
+ 25
+ 18
+ 16
+ 20
+ 20
+ 19
+ 16
+ 22
+ 11
+ 19
+ 12
+ 14
+ 21
+ 19
+ 15
+ 16
+ 35
+ 20
+ 18
+ 14
+ 13
+ 18
+ 18
+ 19
+ 23
+ 19
+ 19
+ 13
+ 288
+ 19
+ 17
+ 17
+ 19
+ 12
+ 18
+ 15
+ 14
+ 13
+ 16
+ 10
+ 12
+ 22
+ 15
+ 13
+ 14
+ 15
+ 22
+ 16
+ 18
+ 13
+ 19
+ 17
+ 17
+ 17
+ 16
+ 16
+ 15
+ 15
+ 24
+ 25
+ 45
+ 23
+ 19
+ 18
+ 23
+ 12
+ 18
+ 20
+ 11
+ 25
+ 16
+ 15
+ 15
+ 200
+ 16
+ 13
+ 19
+ 11
+ 16
+ 19
+ 16
+ 13
+ 14
+ 12
+ 10
+ 17
+ 20
+ 25
+ 17
+ 14
+ 13
+ 20
+ 9
+ 17
+ 13
+ 19
+ 16
+ 27
+ 19
+ 20
+ 16
+ 15
+ 17
+ 15
+ 18
+ 20
+ 17
+ 19
+ 13
+ 21
+ 11
+ 20
+ 19
+ 12
+ 17
+ 23
+ 8
+ 17
+ 13
+ 11
+ 16
+ 29
+ 16
+ 16
+ 20
+ 13
+ 19
+ 20
+ 19
+ 18
+ 22
+ 21
+ 20
+ 15
+ 11
+ 17
+ 17
+ 15
+ 17
+ 13
+ 16
+ 19
+ 20
+ 21
+ 20
+ 18
+ 17
+ 99
+ 14
+ 13
+ 20
+ 16
+ 18
+ 12
+ 15
+ 21
+ 17
+ 18
+ 20
+ 19
+ 12
+ 9
+ 24
+ 10
+ 13
+ 18
+ 16
+ 15
+ 19
+ 13
+ 19
+ 12
+ 22
+ 22
+ 20
+ 17
+ 13
+ 14
+ 14
+ 20
+ 10
+ 19
+ 19
+ 18
+ 20
+ 15
+ 14
+ 13
+ 20
+ 13
+ 14
+ 17
+ 19
+ 16
+ 25
+ 17
+ 15
+ 11
+ 19
+ 19
+ 14
+ 15
+ 15
+ 12
+ 14
+ 16
+ 13
+ 20
+ 16
+ 10
+ 15
+ 20
+ 21
+ 19
+ 17
+ 12
+ 18
+ 17
+ 17
+ 20
+ 14
+ 19
+ 17
+ 19
+ 7
+ 12
+ 17
+ 24
+ 18
+ 17
+ 13
+ 14
+ 16
+ 20
+ 15
+ 10
+ 18
+ 13
+ 18
+ 17
+ 16
+ 13
+ 13
+ 21
+ 13
+ 15
+ 11
+ 15
+ 16
+ 18
+ 13
+ 11
+ 18
+ 13
+ 12
+ 15
+ 17
+ 16
+ 19
+ 12
+ 14
+ 20
+ 13
+ 26
+ 16
+ 20
+ 14
+ 12
+ 18
+ 15
+ 24
+ 14
+ 12
+ 19
+ 19
+ 12
+ 15
+ 18
+ 20
+ 16
+ 17625
+ 17
+ 17
+ 14
+ 22
+ 15
+ 17
+ 19
+ 17
+ 15
+ 16
+ 13
+ 14
+ 18
+ 16
+ 11
+ 20
+ 20
+ 14
+ 19
+ 16
+ 11
+ 12
+ 18
+ 13
+ 8
+ 20
+ 10
+ 17
+ 18
+ 17
+ 21
+ 16
+ 18
+ 16
+ 16
+ 22
+ 19
+ 12
+ 15
+ 14
+ 21
+ 13
+ 16
+ 11
+ 17
+ 12
+ 19
+ 18
+ 18
+ 15
+ 18
+ 12
+ 17
+ 24
+ 12
+ 20
+ 21
+ 14
+ 21
+ 14
+ 21
+ 11
+ 19
+ 13
+ 22
+ 15
+ 17
+ 21
+ 21
+ 22
+ 16
+ 14
+ 21
+ 26
+ 17
+ 21
+ 20
+ 11
+ 12
+ 15
+ 21
+ 19
+ 19
+ 17
+ 22
+ 16
+ 17
+ 18
+ 13
+ 12
+ 13
+ 88
+ 14
+ 14
+ 9
+ 19
+ 18
+ 12
+ 20
+ 16
+ 16
+ 14
+ 17
+ 19
+ 19
+ 6
+ 16
+ 15
+ 20
+ 17
+ 10
+ 19
+ 15
+ 21
+ 20
+ 9
+ 14
+ 17
+ 10
+ 27
+ 22
+ 18
+ 11
+ 19
+ 15
+ 15
+ 19
+ 13
+ 15
+ 24
+ 22
+ 20
+ 19
+ 14
+ 16
+ 17
+ 12
+ 15
+ 22
+ 12
+ 18
+ 19
+ 22
+ 18
+ 23
+ 19
+ 15
+ 15
+ 8
+ 13
+ 24
+ 15
+ 12
+ 30
+ 16
+ 18
+ 15
+ 21
+ 18
+ 14
+ 18
+ 20
+ 17
+ 12
+ 20
+ 19
+ 12
+ 17
+ 13
+ 18
+ 20
+ 16
+ 23
+ 12
+ 17
+ 9
+ 18
+ 13
+ 11
+ 15
+ 14
+ 20
+ 19
+ 16
+ 12
+ 19
+ 19
+ 18
+ 22
+ 23
+ 18
+ 23
+ 18
+ 17
+ 19
+ 22
+ 15
+ 11
+ 17
+ 20
+ 13
+ 19
+ 18
+ 17
+ 18
+ 20
+ 13
+ 14
+ 14
+ 10
+ 22
+ 21
+ 13
+ 19
+ 14
+ 16
+ 14
+ 17
+ 19
+ 14
+ 14
+ 26
+ 21
+ 18
+ 20
+ 11
+ 18
+ 19
+ 20
+ 18
+ 15
+ 15
+ 19
+ 18
+ 15
+ 17
+ 12
+ 15
+ 20
+ 18
+ 14
+ 22
+ 12
+ 13
+ 23
+ 22
+ 17
+ 10
+ 15
+ 19
+ 18
+ 18
+ 17
+ 16
+ 19
+ 13
+ 19
+ 23
+ 15
+ 13
+ 10
+ 14
+ 16
+ 14
+ 17
+ 15
+ 16
+ 20
+ 17
+ 12
+ 20
+ 11
+ 19
+ 11
+ 20
+ 9
+ 27
+ 23
+ 17
+ 18
+ 18
+ 19
+ 20
+ 15
+ 15
+ 18
+ 13
+ 13
+ 21
+ 15
+ 18
+ 13
+ 19
+ 23
+ 19
+ 8
+ 21
+ 19
+ 9
+ 22
+ 15
+ 14
+ 24
+ 17
+ 19
+ 15
+ 22
+ 19
+ 18
+ 13
+ 11
+ 18
+ 13
+ 21
+ 17
+ 12
+ 13
+ 18
+ 11
+ 16
+ 19
+ 16
+ 19
+ 24
+ 15
+ 16
+ 17
+ 18
+ 19
+ 17
+ 19
+ 20
+ 18
+ 14
+ 16
+ 15
+ 20
+ 13
+ 13
+ 16
+ 10
+ 15
+ 29
+ 13
+ 22
+ 18
+ 11
+ 13
+ 18
+ 23
+ 13
+ 11
+ 19
+ 25
+ 18
+ 17
+ 17
+ 20
+ 16
+ 16
+ 22
+ 12
+ 20
+ 39
+ 14
+ 21
+ 19
+ 10
+ 61
+ 18
+ 24
+ 16
+ 14
+ 20
+ 20
+ 19
+ 16
+ 18
+ 11
+ 16
+ 16
+ 20
+ 16
+ 7
+ 16
+ 14
+ 12
+ 24
+ 20
+ 16
+ 17
+ 15
+ 11
+ 20
+ 13
+ 12
+ 25
+ 15
+ 13
+ 15
+ 18
+ 12
+ 6
+ 18
+ 15
+ 24
+ 11
+ 15
+ 14
+ 12
+ 14
+ 15
+ 15
+ 17
+ 20
+ 14
+ 21
+ 17
+ 14
+ 19
+ 22
+ 13
+ 15
+ 12
+ 17
+ 19
+ 23
+ 15
+ 17
+ 25
+ 15
+ 14
+ 23
+ 6
+ 17
+ 9
+ 10
+ 16
+ 17
+ 17
+ 16
+ 18
+ 26
+ 15
+ 17
+ 23
+ 14
+ 11
+ 22
+ 19
+ 21
+ 16
+ 15
+ 21
+ 15
+ 10
+ 22
+ 14
+ 23
+ 12
+ 16
+ 20
+ 13
+ 16
+ 11
+ 19
+ 12
+ 19
+ 16
+ 15
+ 43
+ 18
+ 16
+ 13
+ 27
+ 12
+ 13
+ 14
+ 18
+ 15
+ 14
+ 18
+ 19
+ 14
+ 15
+ 21
+ 15
+ 20
+ 13
+ 21
+ 19
+ 21
+ 18
+ 21
+ 13
+ 24
+ 22
+ 14
+ 22
+ 14
+ 17
+ 21
+ 15
+ 17
+ 14
+ 16
+ 21
+ 11
+ 17
+ 21
+ 26
+ 9
+ 12
+ 17
+ 15
+ 13
+ 13
+ 16
+ 25
+ 23
+ 17
+ 13
+ 20
+ 16
+ 19
+ 17
+ 18
+ 19
+ 17
+ 17
+ 20
+ 17
+ 17
+ 15
+ 20
+ 15
+ 10
+ 13
+ 11
+ 18
+ 9
+ 19
+ 18
+ 28
+ 18
+ 19
+ 18
+ 15
+ 22
+ 16
+ 16
+ 17
+ 15
+ 24
+ 19
+ 16
+ 10
+ 18
+ 16
+ 15
+ 32
+ 17
+ 15
+ 17
+ 18
+ 11
+ 25
+ 15
+ 19
+ 11
+ 20
+ 17
+ 17
+ 20
+ 18
+ 18
+ 16
+ 22
+ 19
+ 15
+ 22
+ 16
+ 14
+ 21
+ 14
+ 14
+ 13
+ 14
+ 14
+ 19
+ 21
+ 18
+ 18
+ 19
+ 12
+ 13
+ 19
+ 19
+ 19
+ 16
+ 18
+ 16
+ 13
+ 17
+ 25
+ 17
+ 18
+ 16
+ 25
+ 25
+ 19
+ 20
+ 13
+ 23
+ 13
+ 14
+ 18
+ 18
+ 20
+ 27
+ 15
+ 23
+ 23
+ 17
+ 25
+ 13
+ 12
+ 19
+ 17
+ 13
+ 25
+ 18
+ 13
+ 12
+ 15
+ 18
+ 16
+ 12
Index: /branches/czw_branch/20101203/psLib/test/math/data/yraw_02.dat
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/data/yraw_02.dat	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/math/data/yraw_02.dat	(revision 30118)
@@ -0,0 +1,984 @@
+ 428
+ 405
+ 820
+ 581
+ 629
+ 396
+ 383
+ 400
+ 631
+ 413
+ 614
+ 379
+ 646
+ 1629
+ 353
+ 2748
+ 400
+ 654
+ 1242
+ 556
+ 1423
+ 524
+ 7261
+ 1997
+ 697
+ 1389
+ 818
+ 26580
+ 495
+ 26915
+ 320
+ 1242
+ 592
+ 490
+ 580
+ 651
+ 421
+ 487
+ 1644
+ 1909
+ 2791
+ 551
+ 386
+ 426
+ 504
+ 995
+ 598
+ 1235
+ 481
+ 589
+ 619
+ 1608
+ 385
+ 687
+ 1119
+ 463
+ 1803
+ 338
+ 427
+ 2509
+ 503
+ 426
+ 1305
+ 425
+ 394
+ 1173
+ 772
+ 672
+ 2239
+ 1171
+ 1117
+ 583
+ 1028
+ 1837
+ 2287
+ 413
+ 762
+ 2109
+ 955
+ 959
+ 1682
+ 1682
+ 1555
+ 481
+ 663
+ 987
+ 415
+ 668
+ 417
+ 1045
+ 2094
+ 464
+ 3437
+ 1566
+ 487
+ 1067
+ 975
+ 1217
+ 6089
+ 383
+ 394
+ 415
+ 1117
+ 522
+ 673
+ 1567
+ 559
+ 15690
+ 325
+ 591
+ 607
+ 634
+ 966
+ 293
+ 1178
+ 334
+ 526
+ 552
+ 994
+ 1852
+ 2689
+ 1175
+ 1221
+ 410
+ 933
+ 1106
+ 1094
+ 7888
+ 461
+ 2142
+ 600
+ 395
+ 1963
+ 663
+ 882
+ 582
+ 456
+ 715
+ 459
+ 1527
+ 1948
+ 1074
+ 1035
+ 556
+ 519
+ 624
+ 728
+ 415
+ 735
+ 414
+ 392
+ 586
+ 745
+ 624
+ 588
+ 912
+ 1550
+ 2030
+ 451
+ 25635
+ 774
+ 395
+ 452
+ 593
+ 644
+ 1807
+ 442
+ 33256
+ 1916
+ 1804
+ 13222
+ 538
+ 1054
+ 433
+ 2055
+ 832
+ 545
+ 924
+ 2808
+ 597
+ 456
+ 833
+ 812
+ 780
+ 422
+ 1189
+ 617
+ 1613
+ 1349
+ 30099
+ 561
+ 2128
+ 1225
+ 1100
+ 415
+ 950
+ 403
+ 34824
+ 496
+ 388
+ 670
+ 372
+ 503
+ 363
+ 604
+ 405
+ 1239
+ 612
+ 300
+ 17802
+ 1560
+ 1123
+ 380
+ 2398
+ 1156
+ 1007
+ 1795
+ 311
+ 370
+ 1905
+ 845
+ 1298
+ 1711
+ 1962
+ 408
+ 1421
+ 638
+ 657
+ 2339
+ 2242
+ 3202
+ 2687
+ 1478
+ 618
+ 19826
+ 1263
+ 359
+ 888
+ 346
+ 673
+ 487
+ 500
+ 2167
+ 1441
+ 382
+ 574
+ 360
+ 859
+ 2557
+ 441
+ 1870
+ 361
+ 524
+ 864
+ 1910
+ 1993
+ 831
+ 542
+ 815
+ 677
+ 321
+ 1018
+ 655
+ 1076
+ 680
+ 779
+ 518
+ 19929
+ 429
+ 514
+ 972
+ 946
+ 388
+ 508
+ 1019
+ 316
+ 17112
+ 640
+ 2896
+ 1328
+ 805
+ 432
+ 345
+ 858
+ 596
+ 488
+ 2105
+ 427
+ 1761
+ 711
+ 689
+ 1003
+ 454
+ 427
+ 499
+ 468
+ 922
+ 394
+ 400
+ 2056
+ 431
+ 433
+ 327
+ 1635
+ 438
+ 462
+ 602
+ 973
+ 761
+ 363
+ 2206
+ 2335
+ 2451
+ 332
+ 1927
+ 1495
+ 649
+ 1112
+ 1036
+ 1360
+ 539
+ 931
+ 1396
+ 408
+ 332
+ 871
+ 449
+ 508
+ 368
+ 1213
+ 400
+ 479
+ 402
+ 1787
+ 426
+ 720
+ 846
+ 869
+ 650
+ 414
+ 413
+ 19125
+ 385
+ 967
+ 1109
+ 22290
+ 918
+ 1752
+ 567
+ 1766
+ 386
+ 1170
+ 619
+ 1963
+ 743
+ 605
+ 740
+ 517
+ 623
+ 631
+ 430
+ 776
+ 750
+ 649
+ 778
+ 922
+ 1194
+ 868
+ 489
+ 770
+ 387
+ 406
+ 545
+ 563
+ 1633
+ 469
+ 3058
+ 1600
+ 918
+ 1546
+ 1969
+ 1611
+ 806
+ 699
+ 583
+ 581
+ 803
+ 657
+ 394
+ 1205
+ 388
+ 709
+ 1174
+ 1849
+ 1571
+ 1051
+ 487
+ 1301
+ 1189
+ 1626
+ 578
+ 398
+ 1514
+ 350
+ 501
+ 535
+ 1079
+ 1743
+ 1426
+ 1074
+ 669
+ 3664
+ 757
+ 517
+ 1027
+ 1097
+ 1264
+ 2322
+ 359
+ 527
+ 664
+ 560
+ 558
+ 22642
+ 331
+ 896
+ 1470
+ 934
+ 467
+ 1019
+ 727
+ 424
+ 353
+ 601
+ 1097
+ 832
+ 510
+ 520
+ 1185
+ 1420
+ 363
+ 965
+ 619
+ 2322
+ 4277
+ 20030
+ 2087
+ 2823
+ 560
+ 19312
+ 1973
+ 770
+ 356
+ 832
+ 2467
+ 342
+ 660
+ 18751
+ 1706
+ 313
+ 1069
+ 2490
+ 1238
+ 1013
+ 1471
+ 3348
+ 760
+ 871
+ 723
+ 397
+ 1104
+ 371
+ 2382
+ 27958
+ 621
+ 339
+ 465
+ 616
+ 2282
+ 524
+ 601
+ 379
+ 587
+ 534
+ 1408
+ 1260
+ 717
+ 1709
+ 965
+ 434
+ 611
+ 1344
+ 387
+ 1660
+ 539
+ 831
+ 401
+ 842
+ 864
+ 1453
+ 1746
+ 468
+ 391
+ 398
+ 376
+ 932
+ 342
+ 483
+ 824
+ 384
+ 991
+ 591
+ 443
+ 419
+ 1112
+ 598
+ 379
+ 549
+ 511
+ 1626
+ 1221
+ 14651
+ 2117
+ 1570
+ 899
+ 1063
+ 994
+ 2198
+ 424
+ 380
+ 2611
+ 3374
+ 533
+ 565
+ 1098
+ 300
+ 857
+ 1517
+ 720
+ 1785
+ 659
+ 9076
+ 1145
+ 476
+ 1588
+ 729
+ 551
+ 667
+ 1041
+ 364
+ 447
+ 406
+ 1271
+ 1515
+ 345
+ 343
+ 577
+ 449
+ 571
+ 1066
+ 1161
+ 1251
+ 332
+ 1669
+ 393
+ 5503
+ 466
+ 481
+ 18535
+ 420
+ 1910
+ 1093
+ 4162
+ 448
+ 660
+ 395
+ 485
+ 450
+ 520
+ 461
+ 406
+ 2414
+ 1150
+ 714
+ 411
+ 18470
+ 1054
+ 401
+ 582
+ 318
+ 404
+ 434
+ 517
+ 3252
+ 1714
+ 997
+ 481
+ 833
+ 504
+ 407
+ 490
+ 1942
+ 439
+ 3112
+ 910
+ 605
+ 727
+ 1347
+ 954
+ 565
+ 493
+ 551
+ 535
+ 416
+ 393
+ 629
+ 4489
+ 395
+ 18156
+ 487
+ 504
+ 618
+ 438
+ 1001
+ 21729
+ 644
+ 1340
+ 390
+ 355
+ 716
+ 911
+ 575
+ 541
+ 2158
+ 8211
+ 959
+ 1004
+ 1370
+ 335
+ 611
+ 385
+ 1382
+ 788
+ 1135
+ 929
+ 2275
+ 653
+ 549
+ 549
+ 1980
+ 390
+ 556
+ 765
+ 1185
+ 1038
+ 493
+ 476
+ 387
+ 1980
+ 3695
+ 808
+ 297
+ 1124
+ 829
+ 378
+ 835
+ 3024
+ 1273
+ 613
+ 1330
+ 473
+ 15685
+ 3112
+ 628
+ 358
+ 1317
+ 607
+ 2270
+ 538
+ 808
+ 1083
+ 287
+ 1598
+ 617
+ 438
+ 398
+ 435
+ 464
+ 476
+ 554
+ 519
+ 507
+ 1171
+ 886
+ 717
+ 545
+ 1698
+ 1063
+ 533
+ 903
+ 464
+ 2416
+ 1608
+ 18915
+ 337
+ 1222
+ 323
+ 981
+ 408
+ 1482
+ 1268
+ 1413
+ 967
+ 392
+ 1373
+ 19138
+ 1133
+ 867
+ 1661
+ 2124
+ 508
+ 304
+ 503
+ 406
+ 14095
+ 1091
+ 370
+ 435
+ 1231
+ 764
+ 499
+ 2387
+ 3092
+ 361
+ 530
+ 945
+ 878
+ 1965
+ 5488
+ 1967
+ 1148
+ 484
+ 565
+ 490
+ 995
+ 1807
+ 733
+ 331
+ 1273
+ 1231
+ 459
+ 14455
+ 1510
+ 555
+ 7084
+ 841
+ 1024
+ 3561
+ 792
+ 440
+ 1821
+ 574
+ 429
+ 1085
+ 691
+ 791
+ 667
+ 1684
+ 622
+ 1019
+ 1704
+ 1105
+ 899
+ 307
+ 1987
+ 352
+ 639
+ 416
+ 428
+ 2525
+ 312
+ 888
+ 444
+ 542
+ 364
+ 327
+ 400
+ 1629
+ 28582
+ 628
+ 332
+ 513
+ 452
+ 361
+ 967
+ 21400
+ 544
+ 1103
+ 1134
+ 29599
+ 638
+ 16500
+ 1148
+ 572
+ 364
+ 776
+ 794
+ 1967
+ 447
+ 1015
+ 433
+ 619
+ 417
+ 897
+ 3099
+ 1957
+ 809
+ 401
+ 442
+ 529
+ 433
+ 350
+ 895
+ 18687
+ 390
+ 553
+ 565
+ 1259
+ 21421
+ 1340
+ 306
+ 2057
+ 473
+ 338
+ 889
+ 320
+ 974
+ 620
+ 1074
+ 1048
+ 325
+ 300
+ 1867
+ 415
+ 358
+ 1721
+ 362
+ 436
+ 435
+ 484
+ 1478
+ 1907
+ 590
+ 2146
+ 7816
+ 583
+ 381
+ 1610
+ 544
+ 376
+ 2144
+ 589
+ 952
+ 389
+ 1145
+ 483
+ 958
+ 854
+ 814
+ 588
+ 25947
+ 659
+ 830
+ 1045
+ 408
+ 880
+ 2352
+ 1651
+ 1288
+ 1022
+ 1976
+ 1292
+ 838
+ 411
+ 796
+ 375
+ 879
+ 2339
+ 1047
+ 945
+ 1922
+ 1322
+ 455
+ 358
+ 677
+ 25142
+ 977
+ 344
+ 1305
+ 421
+ 1119
+ 682
+ 823
+ 1054
+ 554
+ 485
+ 1732
+ 1980
+ 326
+ 444
+ 1762
+ 738
+ 15028
+ 413
+ 349
+ 2474
+ 2837
+ 1074
+ 763
+ 1400
+ 686
+ 1184
+ 491
+ 6502
+ 399
+ 2194
+ 384
+ 968
+ 403
+ 462
+ 499
+ 555
+ 1361
+ 568
+ 1315
+ 3912
+ 514
+ 514
+ 1066
+ 519
+ 1024
+ 1307
+ 1056
+ 402
+ 914
+ 513
+ 444
+ 347
+ 406
+ 506
+ 442
+ 614
+ 356
+ 1222
+ 597
+ 1162
+ 515
+ 22060
+ 2408
+ 2930
+ 5935
+ 1057
+ 747
+ 1396
+ 400
+ 1576
+ 1212
+ 8900
+ 318
+ 688
+ 2122
+ 1771
+ 316
+ 758
+ 445
+ 381
+ 1115
+ 394
+ 2284
+ 1515
+ 1877
+ 637
+ 1279
+ 2291
Index: /branches/czw_branch/20101203/psLib/test/math/data/yraw_03.dat
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/data/yraw_03.dat	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/math/data/yraw_03.dat	(revision 30118)
@@ -0,0 +1,1536 @@
+ 183.6000061
+ 171.3600006
+ 182.5800018
+ 178.5
+ 176.4600067
+ 176.4600067
+ 171.3600006
+ 178.5
+ 183.6000061
+ 175.4400024
+ 159.1199951
+ 180.5399933
+ 183.6000061
+ 187.6799927
+ 175.4400024
+ 181.5599976
+ 174.4199982
+ 179.5200043
+ 180.5399933
+ 187.6799927
+ 183.6000061
+ 171.3600006
+ 177.4799957
+ 192.7799988
+ 184.6199951
+ 176.4600067
+ 178.5
+ 182.5800018
+ 173.3999939
+ 191.7599945
+ 202.9799957
+ 167.2799988
+ 181.5599976
+ 185.6399994
+ 173.3999939
+ 159.1199951
+ 178.5
+ 188.6999969
+ 179.5200043
+ 178.5
+ 184.6199951
+ 175.4400024
+ 186.6600037
+ 179.5200043
+ 183.6000061
+ 182.5800018
+ 173.3999939
+ 181.5599976
+ 184.6199951
+ 177.4799957
+ 162.1799927
+ 186.6600037
+ 163.1999969
+ 199.9199982
+ 173.3999939
+ 170.3399963
+ 184.6199951
+ 190.7400055
+ 173.3999939
+ 178.5
+ 189.7200012
+ 192.7799988
+ 166.2599945
+ 187.6799927
+ 174.4199982
+ 176.4600067
+ 181.5599976
+ 199.9199982
+ 193.8000031
+ 170.3399963
+ 182.5800018
+ 199.9199982
+ 183.6000061
+ 160.1399994
+ 184.6199951
+ 195.8399963
+ 173.3999939
+ 189.7200012
+ 192.7799988
+ 162.1799927
+ 174.4199982
+ 190.7400055
+ 175.4400024
+ 192.7799988
+ 181.5599976
+ 185.6399994
+ 184.6199951
+ 166.2599945
+ 189.7200012
+ 192.7799988
+ 183.6000061
+ 190.7400055
+ 188.6999969
+ 174.4199982
+ 184.6199951
+ 186.6600037
+ 182.5800018
+ 173.3999939
+ 171.3600006
+ 166.2599945
+ 166.2599945
+ 176.4600067
+ 147.8999939
+ 187.6799927
+ 166.2599945
+ 173.3999939
+ 179.5200043
+ 166.2599945
+ 169.3200073
+ 172.3800049
+ 174.4199982
+ 195.8399963
+ 192.7799988
+ 177.4799957
+ 181.5599976
+ 163.1999969
+ 171.3600006
+ 194.8200073
+ 159.1199951
+ 173.3999939
+ 182.5800018
+ 178.5
+ 179.5200043
+ 184.6199951
+ 179.5200043
+ 164.2200012
+ 191.7599945
+ 177.4799957
+ 186.6600037
+ 168.3000031
+ 168.3000031
+ 168.3000031
+ 180.5399933
+ 179.5200043
+ 175.4400024
+ 174.4199982
+ 184.6199951
+ 186.6600037
+ 164.2200012
+ 169.3200073
+ 187.6799927
+ 189.7200012
+ 166.2599945
+ 169.3200073
+ 187.6799927
+ 172.3800049
+ 204
+ 194.8200073
+ 177.4799957
+ 188.6999969
+ 171.3600006
+ 184.6199951
+ 182.5800018
+ 184.6199951
+ 176.4600067
+ 186.6600037
+ 170.3399963
+ 170.3399963
+ 182.5800018
+ 184.6199951
+ 168.3000031
+ 175.4400024
+ 176.4600067
+ 164.2200012
+ 183.6000061
+ 161.1600037
+ 175.4400024
+ 167.2799988
+ 179.5200043
+ 176.4600067
+ 175.4400024
+ 179.5200043
+ 158.1000061
+ 168.3000031
+ 168.3000031
+ 179.5200043
+ 192.7799988
+ 190.7400055
+ 178.5
+ 173.3999939
+ 180.5399933
+ 179.5200043
+ 191.7599945
+ 184.6199951
+ 177.4799957
+ 182.5800018
+ 188.6999969
+ 169.3200073
+ 162.1799927
+ 172.3800049
+ 160.1399994
+ 177.4799957
+ 176.4600067
+ 180.5399933
+ 170.3399963
+ 168.3000031
+ 171.3600006
+ 180.5399933
+ 162.1799927
+ 163.1999969
+ 170.3399963
+ 180.5399933
+ 164.2200012
+ 183.6000061
+ 178.5
+ 193.8000031
+ 177.4799957
+ 178.5
+ 183.6000061
+ 192.7799988
+ 157.0800018
+ 176.4600067
+ 190.7400055
+ 179.5200043
+ 157.0800018
+ 178.5
+ 165.2400055
+ 195.8399963
+ 177.4799957
+ 166.2599945
+ 172.3800049
+ 182.5800018
+ 175.4400024
+ 187.6799927
+ 164.2200012
+ 178.5
+ 173.3999939
+ 173.3999939
+ 173.3999939
+ 172.3800049
+ 183.6000061
+ 181.5599976
+ 163.1999969
+ 179.5200043
+ 193.8000031
+ 172.3800049
+ 158.1000061
+ 171.3600006
+ 165.2400055
+ 183.6000061
+ 187.6799927
+ 158.1000061
+ 171.3600006
+ 168.3000031
+ 166.2599945
+ 166.2599945
+ 178.5
+ 179.5200043
+ 165.2400055
+ 176.4600067
+ 160.1399994
+ 193.8000031
+ 170.3399963
+ 162.1799927
+ 180.5399933
+ 159.1199951
+ 189.7200012
+ 160.1399994
+ 196.8600006
+ 173.3999939
+ 170.3399963
+ 165.2400055
+ 193.8000031
+ 192.7799988
+ 184.6199951
+ 151.9799957
+ 167.2799988
+ 162.1799927
+ 183.6000061
+ 166.2599945
+ 177.4799957
+ 168.3000031
+ 191.7599945
+ 181.5599976
+ 166.2599945
+ 171.3600006
+ 188.6999969
+ 172.3800049
+ 195.8399963
+ 189.7200012
+ 177.4799957
+ 167.2799988
+ 191.7599945
+ 169.3200073
+ 181.5599976
+ 180.5399933
+ 162.1799927
+ 171.3600006
+ 162.1799927
+ 171.3600006
+ 177.4799957
+ 167.2799988
+ 180.5399933
+ 182.5800018
+ 187.6799927
+ 175.4400024
+ 193.8000031
+ 174.4199982
+ 183.6000061
+ 179.5200043
+ 164.2200012
+ 162.1799927
+ 186.6600037
+ 189.7200012
+ 186.6600037
+ 171.3600006
+ 187.6799927
+ 189.7200012
+ 175.4400024
+ 184.6199951
+ 172.3800049
+ 177.4799957
+ 183.6000061
+ 176.4600067
+ 171.3600006
+ 172.3800049
+ 181.5599976
+ 175.4400024
+ 170.3399963
+ 196.8600006
+ 201.9600067
+ 180.5399933
+ 176.4600067
+ 183.6000061
+ 175.4400024
+ 184.6199951
+ 163.1999969
+ 177.4799957
+ 176.4600067
+ 175.4400024
+ 192.7799988
+ 167.2799988
+ 176.4600067
+ 184.6199951
+ 184.6199951
+ 177.4799957
+ 185.6399994
+ 196.8600006
+ 186.6600037
+ 184.6199951
+ 169.3200073
+ 164.2200012
+ 185.6399994
+ 168.3000031
+ 186.6600037
+ 180.5399933
+ 177.4799957
+ 177.4799957
+ 186.6600037
+ 191.7599945
+ 177.4799957
+ 181.5599976
+ 166.2599945
+ 179.5200043
+ 184.6199951
+ 178.5
+ 171.3600006
+ 184.6199951
+ 192.7799988
+ 182.5800018
+ 186.6600037
+ 175.4400024
+ 182.5800018
+ 173.3999939
+ 186.6600037
+ 162.1799927
+ 175.4400024
+ 196.8600006
+ 166.2599945
+ 189.7200012
+ 189.7200012
+ 182.5800018
+ 172.3800049
+ 165.2400055
+ 191.7599945
+ 174.4199982
+ 173.3999939
+ 178.5
+ 171.3600006
+ 157.0800018
+ 182.5800018
+ 161.1600037
+ 195.8399963
+ 186.6600037
+ 167.2799988
+ 166.2599945
+ 182.5800018
+ 178.5
+ 176.4600067
+ 181.5599976
+ 184.6199951
+ 183.6000061
+ 179.5200043
+ 174.4199982
+ 167.2799988
+ 187.6799927
+ 176.4600067
+ 165.2400055
+ 179.5200043
+ 157.0800018
+ 171.3600006
+ 170.3399963
+ 175.4400024
+ 161.1600037
+ 185.6399994
+ 169.3200073
+ 192.7799988
+ 175.4400024
+ 172.3800049
+ 180.5399933
+ 183.6000061
+ 174.4199982
+ 176.4600067
+ 164.2200012
+ 183.6000061
+ 179.5200043
+ 165.2400055
+ 169.3200073
+ 172.3800049
+ 149.9400024
+ 175.4400024
+ 188.6999969
+ 190.7400055
+ 171.3600006
+ 172.3800049
+ 183.6000061
+ 178.5
+ 165.2400055
+ 176.4600067
+ 177.4799957
+ 188.6999969
+ 192.7799988
+ 183.6000061
+ 163.1999969
+ 186.6600037
+ 183.6000061
+ 160.1399994
+ 167.2799988
+ 172.3800049
+ 179.5200043
+ 189.7200012
+ 172.3800049
+ 177.4799957
+ 161.1600037
+ 174.4199982
+ 190.7400055
+ 181.5599976
+ 187.6799927
+ 176.4600067
+ 176.4600067
+ 183.6000061
+ 176.4600067
+ 188.6999969
+ 174.4199982
+ 170.3399963
+ 185.6399994
+ 177.4799957
+ 172.3800049
+ 179.5200043
+ 175.4400024
+ 170.3399963
+ 169.3200073
+ 176.4600067
+ 177.4799957
+ 169.3200073
+ 199.9199982
+ 171.3600006
+ 194.8200073
+ 188.6999969
+ 193.8000031
+ 182.5800018
+ 171.3600006
+ 177.4799957
+ 175.4400024
+ 172.3800049
+ 166.2599945
+ 183.6000061
+ 157.0800018
+ 177.4799957
+ 193.8000031
+ 168.3000031
+ 175.4400024
+ 175.4400024
+ 170.3399963
+ 191.7599945
+ 189.7200012
+ 182.5800018
+ 177.4799957
+ 157.0800018
+ 174.4199982
+ 189.7200012
+ 162.1799927
+ 184.6199951
+ 164.2200012
+ 157.0800018
+ 197.8800049
+ 175.4400024
+ 184.6199951
+ 202.9799957
+ 190.7400055
+ 171.3600006
+ 160.1399994
+ 162.1799927
+ 176.4600067
+ 180.5399933
+ 206.0399933
+ 189.7200012
+ 170.3399963
+ 175.4400024
+ 175.4400024
+ 185.6399994
+ 187.6799927
+ 168.3000031
+ 176.4600067
+ 177.4799957
+ 185.6399994
+ 167.2799988
+ 178.5
+ 182.5800018
+ 179.5200043
+ 173.3999939
+ 185.6399994
+ 196.8600006
+ 183.6000061
+ 162.1799927
+ 176.4600067
+ 189.7200012
+ 208.0800018
+ 177.4799957
+ 163.1999969
+ 187.6799927
+ 196.8600006
+ 180.5399933
+ 188.6999969
+ 163.1999969
+ 187.6799927
+ 168.3000031
+ 182.5800018
+ 181.5599976
+ 174.4199982
+ 181.5599976
+ 161.1600037
+ 163.1999969
+ 184.6199951
+ 190.7400055
+ 181.5599976
+ 185.6399994
+ 186.6600037
+ 173.3999939
+ 172.3800049
+ 179.5200043
+ 187.6799927
+ 191.7599945
+ 190.7400055
+ 183.6000061
+ 166.2599945
+ 196.8600006
+ 172.3800049
+ 174.4199982
+ 181.5599976
+ 177.4799957
+ 176.4600067
+ 188.6999969
+ 184.6199951
+ 169.3200073
+ 178.5
+ 186.6600037
+ 174.4199982
+ 185.6399994
+ 201.9600067
+ 171.3600006
+ 177.4799957
+ 183.6000061
+ 165.2400055
+ 189.7200012
+ 188.6999969
+ 178.5
+ 163.1999969
+ 169.3200073
+ 178.5
+ 182.5800018
+ 173.3999939
+ 177.4799957
+ 165.2400055
+ 163.1999969
+ 175.4400024
+ 184.6199951
+ 189.7200012
+ 186.6600037
+ 188.6999969
+ 163.1999969
+ 158.1000061
+ 172.3800049
+ 186.6600037
+ 173.3999939
+ 157.0800018
+ 158.1000061
+ 172.3800049
+ 197.8800049
+ 171.3600006
+ 172.3800049
+ 184.6199951
+ 173.3999939
+ 174.4199982
+ 175.4400024
+ 166.2599945
+ 166.2599945
+ 172.3800049
+ 171.3600006
+ 181.5599976
+ 181.5599976
+ 187.6799927
+ 180.5399933
+ 169.3200073
+ 182.5800018
+ 178.5
+ 179.5200043
+ 184.6199951
+ 175.4400024
+ 175.4400024
+ 158.1000061
+ 182.5800018
+ 196.8600006
+ 167.2799988
+ 178.5
+ 174.4199982
+ 180.5399933
+ 195.8399963
+ 183.6000061
+ 200.9400024
+ 189.7200012
+ 186.6600037
+ 173.3999939
+ 173.3999939
+ 180.5399933
+ 172.3800049
+ 157.0800018
+ 163.1999969
+ 171.3600006
+ 190.7400055
+ 196.8600006
+ 179.5200043
+ 175.4400024
+ 169.3200073
+ 158.1000061
+ 157.0800018
+ 180.5399933
+ 173.3999939
+ 170.3399963
+ 175.4400024
+ 193.8000031
+ 170.3399963
+ 164.2200012
+ 174.4199982
+ 185.6399994
+ 178.5
+ 176.4600067
+ 176.4600067
+ 179.5200043
+ 176.4600067
+ 171.3600006
+ 205.0200043
+ 184.6199951
+ 180.5399933
+ 165.2400055
+ 167.2799988
+ 162.1799927
+ 165.2400055
+ 180.5399933
+ 169.3200073
+ 176.4600067
+ 182.5800018
+ 182.5800018
+ 175.4400024
+ 186.6600037
+ 182.5800018
+ 183.6000061
+ 163.1999969
+ 161.1600037
+ 189.7200012
+ 181.5599976
+ 187.6799927
+ 173.3999939
+ 173.3999939
+ 177.4799957
+ 179.5200043
+ 198.8999939
+ 177.4799957
+ 183.6000061
+ 154.0200043
+ 188.6999969
+ 181.5599976
+ 177.4799957
+ 174.4199982
+ 202.9799957
+ 168.3000031
+ 164.2200012
+ 187.6799927
+ 171.3600006
+ 189.7200012
+ 185.6399994
+ 187.6799927
+ 157.0800018
+ 193.8000031
+ 160.1399994
+ 166.2599945
+ 193.8000031
+ 166.2599945
+ 168.3000031
+ 179.5200043
+ 181.5599976
+ 172.3800049
+ 183.6000061
+ 184.6199951
+ 180.5399933
+ 177.4799957
+ 192.7799988
+ 171.3600006
+ 197.8800049
+ 190.7400055
+ 182.5800018
+ 178.5
+ 189.7200012
+ 172.3800049
+ 199.9199982
+ 183.6000061
+ 179.5200043
+ 170.3399963
+ 179.5200043
+ 181.5599976
+ 178.5
+ 186.6600037
+ 177.4799957
+ 160.1399994
+ 176.4600067
+ 173.3999939
+ 168.3000031
+ 180.5399933
+ 179.5200043
+ 175.4400024
+ 188.6999969
+ 175.4400024
+ 178.5
+ 161.1600037
+ 181.5599976
+ 184.6199951
+ 169.3200073
+ 187.6799927
+ 164.2200012
+ 176.4600067
+ 176.4600067
+ 174.4199982
+ 189.7200012
+ 192.7799988
+ 181.5599976
+ 165.2400055
+ 173.3999939
+ 184.6199951
+ 164.2200012
+ 181.5599976
+ 167.2799988
+ 157.0800018
+ 175.4400024
+ 172.3800049
+ 172.3800049
+ 170.3399963
+ 166.2599945
+ 185.6399994
+ 175.4400024
+ 184.6199951
+ 179.5200043
+ 198.8999939
+ 189.7200012
+ 164.2200012
+ 198.8999939
+ 169.3200073
+ 183.6000061
+ 191.7599945
+ 168.3000031
+ 178.5
+ 172.3800049
+ 169.3200073
+ 196.8600006
+ 170.3399963
+ 192.7799988
+ 183.6000061
+ 186.6600037
+ 181.5599976
+ 187.6799927
+ 198.8999939
+ 167.2799988
+ 177.4799957
+ 165.2400055
+ 173.3999939
+ 182.5800018
+ 190.7400055
+ 167.2799988
+ 184.6199951
+ 180.5399933
+ 165.2400055
+ 166.2599945
+ 162.1799927
+ 175.4400024
+ 169.3200073
+ 187.6799927
+ 155.0399933
+ 173.3999939
+ 165.2400055
+ 174.4199982
+ 183.6000061
+ 167.2799988
+ 186.6600037
+ 175.4400024
+ 173.3999939
+ 177.4799957
+ 192.7799988
+ 180.5399933
+ 191.7599945
+ 185.6399994
+ 194.8200073
+ 201.9600067
+ 166.2599945
+ 171.3600006
+ 177.4799957
+ 194.8200073
+ 191.7599945
+ 177.4799957
+ 167.2799988
+ 188.6999969
+ 172.3800049
+ 162.1799927
+ 169.3200073
+ 198.8999939
+ 183.6000061
+ 170.3399963
+ 190.7400055
+ 170.3399963
+ 169.3200073
+ 185.6399994
+ 181.5599976
+ 166.2599945
+ 187.6799927
+ 169.3200073
+ 157.0800018
+ 165.2400055
+ 176.4600067
+ 174.4199982
+ 166.2599945
+ 177.4799957
+ 195.8399963
+ 187.6799927
+ 186.6600037
+ 194.8200073
+ 181.5599976
+ 172.3800049
+ 166.2599945
+ 168.3000031
+ 183.6000061
+ 168.3000031
+ 174.4199982
+ 185.6399994
+ 180.5399933
+ 181.5599976
+ 189.7200012
+ 172.3800049
+ 183.6000061
+ 187.6799927
+ 183.6000061
+ 200.9400024
+ 184.6199951
+ 173.3999939
+ 176.4600067
+ 172.3800049
+ 169.3200073
+ 166.2599945
+ 186.6600037
+ 181.5599976
+ 161.1600037
+ 182.5800018
+ 179.5200043
+ 178.5
+ 174.4199982
+ 170.3399963
+ 179.5200043
+ 193.8000031
+ 188.6999969
+ 146.8800049
+ 192.7799988
+ 171.3600006
+ 178.5
+ 177.4799957
+ 184.6199951
+ 180.5399933
+ 163.1999969
+ 159.1199951
+ 160.1399994
+ 178.5
+ 176.4600067
+ 176.4600067
+ 192.7799988
+ 161.1600037
+ 166.2599945
+ 162.1799927
+ 172.3800049
+ 175.4400024
+ 168.3000031
+ 201.9600067
+ 188.6999969
+ 185.6399994
+ 175.4400024
+ 175.4400024
+ 182.5800018
+ 182.5800018
+ 172.3800049
+ 175.4400024
+ 179.5200043
+ 184.6199951
+ 163.1999969
+ 195.8399963
+ 180.5399933
+ 170.3399963
+ 212.1600037
+ 166.2599945
+ 187.6799927
+ 179.5200043
+ 178.5
+ 176.4600067
+ 172.3800049
+ 183.6000061
+ 179.5200043
+ 176.4600067
+ 185.6399994
+ 161.1600037
+ 187.6799927
+ 167.2799988
+ 187.6799927
+ 199.9199982
+ 187.6799927
+ 169.3200073
+ 158.1000061
+ 200.9400024
+ 191.7599945
+ 179.5200043
+ 170.3399963
+ 186.6600037
+ 170.3399963
+ 184.6199951
+ 189.7200012
+ 197.8800049
+ 186.6600037
+ 171.3600006
+ 164.2200012
+ 183.6000061
+ 180.5399933
+ 165.2400055
+ 160.1399994
+ 183.6000061
+ 166.2599945
+ 183.6000061
+ 196.8600006
+ 175.4400024
+ 172.3800049
+ 172.3800049
+ 181.5599976
+ 177.4799957
+ 173.3999939
+ 176.4600067
+ 180.5399933
+ 176.4600067
+ 178.5
+ 163.1999969
+ 189.7200012
+ 175.4400024
+ 174.4199982
+ 185.6399994
+ 182.5800018
+ 169.3200073
+ 194.8200073
+ 192.7799988
+ 188.6999969
+ 193.8000031
+ 175.4400024
+ 165.2400055
+ 180.5399933
+ 184.6199951
+ 176.4600067
+ 171.3600006
+ 188.6999969
+ 199.9199982
+ 183.6000061
+ 169.3200073
+ 175.4400024
+ 180.5399933
+ 174.4199982
+ 167.2799988
+ 184.6199951
+ 177.4799957
+ 180.5399933
+ 180.5399933
+ 184.6199951
+ 178.5
+ 186.6600037
+ 161.1600037
+ 183.6000061
+ 168.3000031
+ 188.6999969
+ 184.6199951
+ 171.3600006
+ 185.6399994
+ 167.2799988
+ 162.1799927
+ 186.6600037
+ 175.4400024
+ 166.2599945
+ 182.5800018
+ 171.3600006
+ 176.4600067
+ 192.7799988
+ 178.5
+ 168.3000031
+ 182.5800018
+ 184.6199951
+ 148.9199982
+ 172.3800049
+ 168.3000031
+ 181.5599976
+ 154.0200043
+ 166.2599945
+ 174.4199982
+ 166.2599945
+ 178.5
+ 184.6199951
+ 176.4600067
+ 171.3600006
+ 188.6999969
+ 177.4799957
+ 172.3800049
+ 176.4600067
+ 179.5200043
+ 176.4600067
+ 161.1600037
+ 166.2599945
+ 181.5599976
+ 170.3399963
+ 176.4600067
+ 163.1999969
+ 183.6000061
+ 206.0399933
+ 171.3600006
+ 186.6600037
+ 176.4600067
+ 163.1999969
+ 179.5200043
+ 176.4600067
+ 182.5800018
+ 167.2799988
+ 174.4199982
+ 188.6999969
+ 177.4799957
+ 190.7400055
+ 176.4600067
+ 175.4400024
+ 174.4199982
+ 179.5200043
+ 182.5800018
+ 182.5800018
+ 175.4400024
+ 165.2400055
+ 180.5399933
+ 178.5
+ 176.4600067
+ 191.7599945
+ 173.3999939
+ 186.6600037
+ 165.2400055
+ 173.3999939
+ 188.6999969
+ 172.3800049
+ 168.3000031
+ 193.8000031
+ 180.5399933
+ 172.3800049
+ 180.5399933
+ 189.7200012
+ 170.3399963
+ 170.3399963
+ 195.8399963
+ 173.3999939
+ 187.6799927
+ 165.2400055
+ 147.8999939
+ 173.3999939
+ 184.6199951
+ 171.3600006
+ 178.5
+ 163.1999969
+ 171.3600006
+ 190.7400055
+ 180.5399933
+ 156.0599976
+ 164.2200012
+ 172.3800049
+ 202.9799957
+ 201.9600067
+ 175.4400024
+ 193.8000031
+ 176.4600067
+ 182.5800018
+ 184.6199951
+ 178.5
+ 169.3200073
+ 166.2599945
+ 173.3999939
+ 182.5800018
+ 171.3600006
+ 167.2799988
+ 185.6399994
+ 179.5200043
+ 188.6999969
+ 194.8200073
+ 177.4799957
+ 177.4799957
+ 164.2200012
+ 189.7200012
+ 193.8000031
+ 173.3999939
+ 178.5
+ 184.6199951
+ 191.7599945
+ 191.7599945
+ 162.1799927
+ 171.3600006
+ 165.2400055
+ 197.8800049
+ 169.3200073
+ 178.5
+ 174.4199982
+ 183.6000061
+ 189.7200012
+ 181.5599976
+ 185.6399994
+ 179.5200043
+ 181.5599976
+ 161.1600037
+ 173.3999939
+ 187.6799927
+ 177.4799957
+ 182.5800018
+ 171.3600006
+ 188.6999969
+ 194.8200073
+ 176.4600067
+ 182.5800018
+ 157.0800018
+ 169.3200073
+ 170.3399963
+ 168.3000031
+ 190.7400055
+ 170.3399963
+ 185.6399994
+ 195.8399963
+ 172.3800049
+ 213.1799927
+ 187.6799927
+ 187.6799927
+ 178.5
+ 181.5599976
+ 183.6000061
+ 163.1999969
+ 169.3200073
+ 180.5399933
+ 204
+ 175.4400024
+ 158.1000061
+ 174.4199982
+ 183.6000061
+ 181.5599976
+ 181.5599976
+ 180.5399933
+ 172.3800049
+ 188.6999969
+ 166.2599945
+ 196.8600006
+ 187.6799927
+ 196.8600006
+ 164.2200012
+ 160.1399994
+ 165.2400055
+ 172.3800049
+ 177.4799957
+ 173.3999939
+ 168.3000031
+ 181.5599976
+ 164.2200012
+ 177.4799957
+ 182.5800018
+ 162.1799927
+ 168.3000031
+ 181.5599976
+ 179.5200043
+ 171.3600006
+ 173.3999939
+ 176.4600067
+ 197.8800049
+ 172.3800049
+ 189.7200012
+ 172.3800049
+ 161.1600037
+ 183.6000061
+ 173.3999939
+ 188.6999969
+ 161.1600037
+ 180.5399933
+ 160.1399994
+ 166.2599945
+ 164.2200012
+ 182.5800018
+ 169.3200073
+ 176.4600067
+ 186.6600037
+ 192.7799988
+ 163.1999969
+ 153
+ 182.5800018
+ 184.6199951
+ 166.2599945
+ 167.2799988
+ 186.6600037
+ 177.4799957
+ 174.4199982
+ 175.4400024
+ 164.2200012
+ 180.5399933
+ 178.5
+ 176.4600067
+ 164.2200012
+ 160.1399994
+ 178.5
+ 176.4600067
+ 180.5399933
+ 182.5800018
+ 179.5200043
+ 169.3200073
+ 178.5
+ 172.3800049
+ 171.3600006
+ 178.5
+ 166.2599945
+ 171.3600006
+ 181.5599976
+ 162.1799927
+ 157.0800018
+ 189.7200012
+ 177.4799957
+ 164.2200012
+ 179.5200043
+ 187.6799927
+ 172.3800049
+ 158.1000061
+ 164.2200012
+ 177.4799957
+ 165.2400055
+ 185.6399994
+ 174.4199982
+ 188.6999969
+ 173.3999939
+ 168.3000031
+ 164.2200012
+ 187.6799927
+ 209.1000061
+ 172.3800049
+ 177.4799957
+ 170.3399963
+ 172.3800049
+ 164.2200012
+ 190.7400055
+ 177.4799957
+ 165.2400055
+ 168.3000031
+ 173.3999939
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
Index: /branches/czw_branch/20101203/psLib/test/math/data/yraw_04.dat
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/data/yraw_04.dat	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/math/data/yraw_04.dat	(revision 30118)
@@ -0,0 +1,500 @@
+-1.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.963289
+-1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -0.915174
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -0.853025
+ 0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.989926
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.834902
+ -1.000000
+ -1.000000
+-0.942985
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -0.990081
+ -1.000000
+ -0.990456
+ -0.814654
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-0.968021
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -0.993967
+ -0.957540
+-0.894533
+ -0.958363
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.988915
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.985367
+ -1.000000
+ -0.972040
+ -1.000000
+-1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -0.882278
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -0.962575
+ -0.976843
+ -0.998926
+ -1.000000
+ -0.914090
+ 0.000000
+ -0.957808
+-1.000000
+ -1.000000
+ -1.000000
+ 0.000000
+ -0.902593
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.975404
+-1.000000
+ 0.000000
+ -0.984627
+ -1.000000
+ -0.969547
+ -0.851295
+ -1.000000
+ -0.988146
+-1.000000
+ 0.000000
+ -1.000000
+ -0.993753
+ -0.861851
+ -1.000000
+ -0.980836
+ -0.979644
+-1.000000
+ -1.000000
+ -1.000000
+ -0.995401
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+0.000000
+ -1.000000
+ -0.990123
+ -0.944934
+ -1.000000
+ 0.000000
+ -1.000000
+ -0.952198
+-1.000000
+ -1.000000
+ -0.960814
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.956806
+ -1.000000
+0.000000
+ -0.991778
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+-0.977640
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -0.977630
+ -1.000000
+ -0.974242
+-1.000000
+ -1.000000
+ -0.940085
+ -0.930729
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+-1.000000
+ -0.933695
+ -1.000000
+ -0.932306
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.836774
+-0.931762
+ -0.926990
+ -0.861895
+ -1.000000
+ -0.922505
+ -1.000000
+ -0.956420
+ -0.998768
+-0.974626
+ -0.964573
+ -1.000000
+ -0.933995
+ -1.000000
+ -0.995117
+ -1.000000
+ -1.000000
+0.000000
+ 0.000000
+ -1.000000
+ -0.955537
+ -0.996360
+ -0.988015
+ -1.000000
+ -1.000000
+-0.963953
+ -0.920429
+ -0.955252
+ -0.950946
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.979526
+-1.000000
+ -1.000000
+ -0.997193
+ -1.000000
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -0.893445
+ -1.000000
+ -1.000000
+ -0.997704
+ -1.000000
+ -1.000000
+ -0.952295
+-1.000000
+ 0.000000
+ -0.928042
+ -1.000000
+ -1.000000
+ -0.994029
+ -0.919350
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -0.958966
+ -0.806458
+ -0.903843
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ 0.000000
+ -0.989002
+ 0.000000
+ -0.999874
+-1.000000
+ 0.000000
+ -1.000000
+ 0.000000
+ -0.923556
+ -0.906242
+ -0.923497
+ -0.997873
+-1.000000
+ -1.000000
+ 0.000000
+ -0.960376
+ -0.998760
+ -1.000000
+ 0.000000
+ -1.000000
+-0.852141
+ -1.000000
+ -0.957442
+ -0.942000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+-1.000000
+ -1.000000
+ -0.996748
+ -0.997676
+ -0.976159
+ -0.951572
+ -1.000000
+ -0.993083
+-0.715375
+ -0.997984
+ -1.000000
+ -0.962484
+ -0.996733
+ -1.000000
+ -1.000000
+ -0.953423
+-1.000000
+ -0.882232
+ -1.000000
+ -1.000000
+ -0.944493
+ -1.000000
+ -0.979617
+ -1.000000
+-0.990002
+ -1.000000
+ -0.844745
+ -0.945080
+ -1.000000
+ -1.000000
+ -0.904816
+ -1.000000
+-0.986999
+ -1.000000
+ -0.854941
+ -1.000000
+ -0.946096
+ -0.977678
+ -1.000000
+ -0.955933
+-0.979545
+ -1.000000
+ -1.000000
+ -0.863616
+ -0.973953
+ -0.996599
+ -0.990304
+ -0.978263
+-1.000000
+ -0.967798
+ -0.912566
+ 0.000000
+ -1.000000
+ -1.000000
+ -0.990321
+ -0.995921
+-1.000000
+ -1.000000
+ -1.000000
+ -0.927030
+ -0.886393
+ -0.987297
+ -1.000000
+ -1.000000
+-0.987206
+ -0.978084
+ -1.000000
+ -0.923876
+ -0.957539
+ -0.991587
+ -0.819295
+ -1.000000
+-0.985077
+ -1.000000
+ 0.000000
+ -1.000000
+ -1.000000
+ -0.822353
+ -1.000000
+ -1.000000
+-0.987783
+ -1.000000
+ -0.909520
+ -1.000000
+ -0.932334
+ -0.991847
+ -1.000000
+ -0.885318
+-0.945695
+ -0.977144
+ -0.989444
+ -0.887085
+ -0.891662
+ -0.894193
+ -1.000000
+ 0.000000
+-1.000000
+ -0.917484
+ -1.000000
+ -0.892801
+ -1.000000
+ -0.963580
+ -0.869279
+ -0.965420
+-0.906966
+ -0.929646
+ -0.981315
+ -1.000000
+ -1.000000
+ -0.749674
+ -1.000000
+ -0.886804
+-1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -1.000000
+ -0.970826
+ -0.909766
+-1.000000
+ -0.910406
+ -0.983636
+ -1.000000
+ -0.961209
+ -0.935273
+ -1.000000
+ -0.989806
+0.000000
+ -0.981563
+ -0.989701
+ -0.915626
+ -0.997493
+ -0.981429
+ -1.000000
+ -0.964583
+-1.000000
+ -0.930216
+ -0.737797
+ -1.000000
+ -0.944314
+ -0.999998
+ -0.999611
+ -0.945788
+-0.773886
+ -0.848979
+ -0.980186
+ -1.000000
+ -1.000000
+ 0.000000
+ -0.951392
+ -0.993398
+-0.931889
+ -0.991680
+ -0.959021
+ -0.904240
+ -1.000000
+ -0.983561
+ -0.821324
+ 0.000000
+0.000000
+ -1.000000
+ -0.925782
+ -0.841267
+ -1.000000
+ -0.907313
+ -1.000000
+ -0.990704
+-1.000000
+ -1.000000
+ -0.936372
+ -0.885059
Index: /branches/czw_branch/20101203/psLib/test/math/mana.stats.pro
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/mana.stats.pro	(revision 30118)
+++ /branches/czw_branch/20101203/psLib/test/math/mana.stats.pro	(revision 30118)
@@ -0,0 +1,47 @@
+
+macro makegauss
+  if ($0 != 6)
+    echo "USAGE: makegauss (Io) (mean) (sigma) (dy) (color)"
+    break
+  end
+
+  set f = $1*exp(-0.5*($4-$2)^2 / $3^2)
+  plot -c $5 $4 f -x 0
+end
+
+macro plot1
+  data data/yraw_01.dat
+  read y 1
+  histogram y ny 0 100 1 -range dy
+  lim dy ny; clear; box; plot dy ny -x 1
+  makegauss 100 16.334488 3.818669 dy red
+  makegauss 100 16.773050 3.790289 dy blue
+end  
+
+macro plot2
+  data data/yraw_02.dat
+  read y 1
+  histogram y ny 0 10000 10 -range dy
+  lim dy ny; clear; box; plot dy ny -x 1
+  makegauss 10 746.773743 621.665955 dy red
+  makegauss 10 899.454041 568.609497 dy blue
+end  
+
+macro plot3
+  data data/yraw_03.dat
+  read y 1
+  histogram y ny -1 1000 1 -range dy
+  lim 100 300 -1 60; clear; box; plot dy ny -x 1
+  makegauss 47 175.329529 14.232742 dy red ; # robust
+  makegauss 47 148.204117 66.969803 dy blue ; # clipped
+  makegauss 47 178.721268 10.870105 dy green ; # fitted v2
+end  
+
+macro plot4
+  data data/yraw_04.dat
+  read y 1
+  histogram y ny -1.1 0.1 0.01 -range dy
+  lim dy ny; clear; box; plot dy ny -x 1
+  makegauss 100 -0.984124 0.029106 dy red
+  makegauss 100 -1.000000 0.029106 dy blue
+end  
Index: /branches/czw_branch/20101203/psLib/test/math/tap_psStats_Sample_01.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/math/tap_psStats_Sample_01.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/test/math/tap_psStats_Sample_01.c	(revision 30118)
@@ -487,16 +487,81 @@
                          };
 
+static float yraw_04[] = {
+    -1.000000, 0.000000, 0.000000, 0.000000, 0.000000, -1.000000, -1.000000, -1.000000,
+    0.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -0.963289,
+    -1.000000, 0.000000, -1.000000, -1.000000, -0.915174, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, 0.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -0.853025, 0.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -0.989926, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -0.834902, -1.000000, -1.000000,
+    -0.942985, -1.000000, -1.000000, 0.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -0.990081, -1.000000, -0.990456, -0.814654, -1.000000, -1.000000,
+    -1.000000, -1.000000, 0.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -0.968021, -1.000000, -1.000000, 0.000000, -1.000000, -1.000000, -0.993967, -0.957540,
+    -0.894533, -0.958363, -1.000000, -1.000000, -1.000000, -0.988915, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -0.985367, -1.000000, -0.972040, -1.000000,
+    -1.000000, -1.000000, 0.000000, -1.000000, -0.882278, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -0.962575, -0.976843, -0.998926, -1.000000, -0.914090, 0.000000, -0.957808,
+    -1.000000, -1.000000, -1.000000, 0.000000, -0.902593, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -0.975404,
+    -1.000000, 0.000000, -0.984627, -1.000000, -0.969547, -0.851295, -1.000000, -0.988146,
+    -1.000000, 0.000000, -1.000000, -0.993753, -0.861851, -1.000000, -0.980836, -0.979644,
+    -1.000000, -1.000000, -1.000000, -0.995401, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000,
+    0.000000, -1.000000, -0.990123, -0.944934, -1.000000, 0.000000, -1.000000, -0.952198,
+    -1.000000, -1.000000, -0.960814, -1.000000, -1.000000, -1.000000, -0.956806, -1.000000,
+    0.000000, -0.991778, -1.000000, -1.000000, -1.000000, -1.000000, 0.000000, -1.000000,
+    -0.977640, -1.000000, -1.000000, 0.000000, -1.000000, -0.977630, -1.000000, -0.974242,
+    -1.000000, -1.000000, -0.940085, -0.930729, -1.000000, -1.000000, 0.000000, -1.000000,
+    -1.000000, -0.933695, -1.000000, -0.932306, -1.000000, -1.000000, -1.000000, -0.836774,
+    -0.931762, -0.926990, -0.861895, -1.000000, -0.922505, -1.000000, -0.956420, -0.998768,
+    -0.974626, -0.964573, -1.000000, -0.933995, -1.000000, -0.995117, -1.000000, -1.000000,
+    0.000000, 0.000000, -1.000000, -0.955537, -0.996360, -0.988015, -1.000000, -1.000000,
+    -0.963953, -0.920429, -0.955252, -0.950946, -1.000000, -1.000000, -1.000000, -0.979526,
+    -1.000000, -1.000000, -0.997193, -1.000000, -1.000000, 0.000000, -1.000000, -1.000000,
+    -1.000000, -0.893445, -1.000000, -1.000000, -0.997704, -1.000000, -1.000000, -0.952295,
+    -1.000000, 0.000000, -0.928042, -1.000000, -1.000000, -0.994029, -0.919350, -1.000000,
+    -1.000000, -1.000000, -1.000000, -0.958966, -0.806458, -0.903843, -1.000000, -1.000000,
+    -1.000000, -1.000000, -1.000000, -1.000000, 0.000000, -0.989002, 0.000000, -0.999874,
+    -1.000000, 0.000000, -1.000000, 0.000000, -0.923556, -0.906242, -0.923497, -0.997873,
+    -1.000000, -1.000000, 0.000000, -0.960376, -0.998760, -1.000000, 0.000000, -1.000000,
+    -0.852141, -1.000000, -0.957442, -0.942000, -1.000000, -1.000000, -1.000000, -1.000000,
+    -1.000000, -1.000000, -0.996748, -0.997676, -0.976159, -0.951572, -1.000000, -0.993083,
+    -0.715375, -0.997984, -1.000000, -0.962484, -0.996733, -1.000000, -1.000000, -0.953423,
+    -1.000000, -0.882232, -1.000000, -1.000000, -0.944493, -1.000000, -0.979617, -1.000000,
+    -0.990002, -1.000000, -0.844745, -0.945080, -1.000000, -1.000000, -0.904816, -1.000000,
+    -0.986999, -1.000000, -0.854941, -1.000000, -0.946096, -0.977678, -1.000000, -0.955933,
+    -0.979545, -1.000000, -1.000000, -0.863616, -0.973953, -0.996599, -0.990304, -0.978263,
+    -1.000000, -0.967798, -0.912566, 0.000000, -1.000000, -1.000000, -0.990321, -0.995921,
+    -1.000000, -1.000000, -1.000000, -0.927030, -0.886393, -0.987297, -1.000000, -1.000000,
+    -0.987206, -0.978084, -1.000000, -0.923876, -0.957539, -0.991587, -0.819295, -1.000000,
+    -0.985077, -1.000000, 0.000000, -1.000000, -1.000000, -0.822353, -1.000000, -1.000000,
+    -0.987783, -1.000000, -0.909520, -1.000000, -0.932334, -0.991847, -1.000000, -0.885318,
+    -0.945695, -0.977144, -0.989444, -0.887085, -0.891662, -0.894193, -1.000000, 0.000000,
+    -1.000000, -0.917484, -1.000000, -0.892801, -1.000000, -0.963580, -0.869279, -0.965420,
+    -0.906966, -0.929646, -0.981315, -1.000000, -1.000000, -0.749674, -1.000000, -0.886804,
+    -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -1.000000, -0.970826, -0.909766,
+    -1.000000, -0.910406, -0.983636, -1.000000, -0.961209, -0.935273, -1.000000, -0.989806,
+    0.000000, -0.981563, -0.989701, -0.915626, -0.997493, -0.981429, -1.000000, -0.964583,
+    -1.000000, -0.930216, -0.737797, -1.000000, -0.944314, -0.999998, -0.999611, -0.945788,
+    -0.773886, -0.848979, -0.980186, -1.000000, -1.000000, 0.000000, -0.951392, -0.993398,
+    -0.931889, -0.991680, -0.959021, -0.904240, -1.000000, -0.983561, -0.821324, 0.000000,
+    0.000000, -1.000000, -0.925782, -0.841267, -1.000000, -0.907313, -1.000000, -0.990704,
+    -1.000000, -1.000000, -0.936372, -0.885059
+};
+
 int main (void)
 {
     plan_tests(21);
 
-//    diag("psStats Tests with sample SDSS data from RHL and Megacam from EAM");
-//    diag("this file does not yet define a specific test");
-//    diag("the fitted mean is currently wrong for these two data sets");
-
-    {
+    // float **yraw = {yraw_01, yraw_02, yraw_03, yraw_04, NULL};
+
+    if (1) {
+	diag("sample 1 : problem with integer-binned data driven to tiny sigma values");
+
         psMemId id = psMemGetId();
 
-//        diag("sample 1 : problem with integer-binned data driven to tiny sigma values");
         psStats *stats = psStatsAlloc (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV |
                                        PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV |
@@ -505,5 +570,4 @@
                                        PS_STAT_SAMPLE_STDEV | PS_STAT_USE_BINSIZE);
         stats->binsize = 1.0;
-
 
         // copy data in static array
@@ -533,8 +597,8 @@
 
 
-    {
+    if (1) {
         psMemId id = psMemGetId();
 
-//        diag("sample 2");
+        diag("sample 2");
         psStats *stats = psStatsAlloc (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV |
                                        PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV |
@@ -568,15 +632,13 @@
     }
 
-    {
+    if (1) {
         psMemId id = psMemGetId();
 
-//        diag("sample 3");
+        diag("sample 3");
         psStats *stats = psStatsAlloc (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV |
                                        PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV |
                                        PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV |
                                        PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN |
-                                       PS_STAT_SAMPLE_STDEV | PS_STAT_USE_BINSIZE);
-        stats->binsize = 1.0;
-
+                                       PS_STAT_SAMPLE_STDEV);
 
         // copy data in static array
@@ -605,4 +667,42 @@
     }
 
+    {
+        psMemId id = psMemGetId();
+
+	// psTraceSetLevel("psLib.math.vectorRobustStats", 6);
+
+        diag("sample 4");
+        psStats *stats = psStatsAlloc (PS_STAT_FITTED_MEAN | PS_STAT_FITTED_STDEV |
+                                       PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV |
+                                       PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV |
+                                       PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_MEDIAN |
+                                       PS_STAT_SAMPLE_STDEV);
+
+        // copy data in static array
+        int nPts = sizeof(yraw_04) / sizeof (float);
+        psVector *y = psVectorAlloc (nPts, PS_TYPE_F32);
+        for (int i = 0; i < y->n; i++) {
+            y->data.F32[i] = yraw_04[i];
+        }
+
+        psVectorStats (stats, y, NULL, NULL, 1);
+        ok (1, "sample  mean   %f, stdev %f", stats->sampleMean,   stats->sampleStdev);
+        ok (1, "sample  median %f, stdev %f", stats->sampleMedian, stats->sampleStdev);
+        ok (1, "clipped mean   %f, stdev %f", stats->clippedMean,  stats->clippedStdev);
+        ok (1, "robust  median %f, stdev %f", stats->robustMedian, stats->robustStdev);
+        ok (1, "fitted  mean   %f, stdev %f", stats->fittedMean,   stats->fittedStdev);
+        psFree (stats);
+
+        stats = psStatsAlloc (PS_STAT_FITTED_MEAN_V2 | PS_STAT_FITTED_STDEV_V2 | PS_STAT_USE_BINSIZE);
+        stats->binsize = 1.0;
+        psVectorStats (stats, y, NULL, NULL, 1);
+        ok (1, "fitted  mean v2 %f, stdev %f", stats->fittedMean,   stats->fittedStdev);
+        psFree (stats);
+
+        psFree (y);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+    }
+
     return exit_status();
 }
+
Index: /branches/czw_branch/20101203/psLib/test/types/tap_psMetadataConfigWrite.c
===================================================================
--- /branches/czw_branch/20101203/psLib/test/types/tap_psMetadataConfigWrite.c	(revision 30117)
+++ /branches/czw_branch/20101203/psLib/test/types/tap_psMetadataConfigWrite.c	(revision 30118)
@@ -25,5 +25,5 @@
     {
         psMemId id = psMemGetId();
-        ok( !psMetadataConfigWrite(NULL, "mdcfg.wrt"),
+        ok( !psMetadataConfigWrite(NULL, "mdcfg.wrt", NULL),
             "return false for NULL metadata input.");
         ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
@@ -35,5 +35,5 @@
         psMemId id = psMemGetId();
         psMetadata *md = psMetadataAlloc();
-        ok( !psMetadataConfigWrite(md, NULL),
+        ok( !psMetadataConfigWrite(md, NULL, NULL),
             "return false for NULL filename input.");
         psFree(md);
@@ -46,5 +46,5 @@
         psMemId id = psMemGetId();
         psMetadata *md = psMetadataAlloc();
-        ok( !psMetadataConfigWrite(md, "."),
+        ok( !psMetadataConfigWrite(md, ".", NULL),
             "return false for invalid filename input.");
         psFree(md);
@@ -57,5 +57,5 @@
         psMemId id = psMemGetId();
         psMetadata *md = psMetadataAlloc();
-        ok(psMetadataConfigWrite(md, "mdcfg.wrt"), "return false for empty metadata input.");
+        ok(psMetadataConfigWrite(md, "mdcfg.wrt", NULL), "return false for empty metadata input.");
         psFree(md);
         ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
@@ -68,5 +68,5 @@
         psMetadata *md = psMetadataAlloc();
         psMetadataAddBool(md, PS_LIST_TAIL, "item1-1", 0, "I am a boolean", true);
-        ok( psMetadataConfigWrite(md, "mdcfg.wrt"),
+        ok( psMetadataConfigWrite(md, "mdcfg.wrt", NULL),
             "return true for valid inputs.");
         char configTest[61];
Index: /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.c	(revision 30118)
@@ -49,4 +49,54 @@
 }
 
+bool pmReadoutSetFileStatus(pmReadout *readout, bool status)
+{
+    PS_ASSERT_PTR_NON_NULL(readout, false);
+
+    readout->file_exists = status;
+    return true;
+}
+
+bool pmFPAviewSetFileStatus (pmFPA *fpa, const pmFPAview *view, bool status) {
+
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (view->chip == -1) {
+	bool set = pmFPASetFileStatus (fpa, status);
+        return set;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %ld", view->chip, fpa->chips->n);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        bool set = pmChipSetFileStatus (chip, status);
+        return set;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %ld", view->cell, chip->cells->n);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        bool set = pmCellSetFileStatus (cell, status);
+        return set;
+    }
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouds->n == %ld", view->readout, cell->readouts->n);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    bool set = pmReadoutSetFileStatus (readout, status);
+    return set;
+}
+
 bool pmFPACheckFileStatus(const pmFPA *fpa)
 {
@@ -125,7 +175,57 @@
     for (int i = 0; i < cell->readouts->n; i++) {
         pmReadout *readout = cell->readouts->data[i];
-        readout->data_exists = status;
-    }
-    return true;
+        pmReadoutSetDataStatus(readout, status);
+    }
+    return true;
+}
+
+bool pmReadoutSetDataStatus (pmReadout *readout, bool status)
+{
+    PS_ASSERT_PTR_NON_NULL(readout, false);
+
+    readout->data_exists = status;
+    return true;
+}
+
+bool pmFPAviewSetDataStatus (pmFPA *fpa, const pmFPAview *view, bool status) {
+
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (view->chip == -1) {
+	bool set = pmFPASetDataStatus (fpa, status);
+        return set;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %ld", view->chip, fpa->chips->n);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        bool set = pmChipSetDataStatus (chip, status);
+        return set;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %ld", view->cell, chip->cells->n);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        bool set = pmCellSetDataStatus (cell, status);
+        return set;
+    }
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouds->n == %ld", view->readout, cell->readouts->n);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    bool set = pmReadoutSetDataStatus (readout, status);
+    return set;
 }
 
Index: /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.h
===================================================================
--- /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.h	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/camera/pmFPAFlags.h	(revision 30118)
@@ -34,4 +34,8 @@
                         );
 
+bool pmReadoutSetFileStatus(pmReadout *readout, bool status);
+
+bool pmFPAviewSetFileStatus (pmFPA *fpa, const pmFPAview *view, bool status);
+
 // Functions to check the file_exists flags
 
@@ -65,4 +69,7 @@
                         );
 
+bool pmReadoutSetDataStatus (pmReadout *readout, bool status);
+
+bool pmFPAviewSetDataStatus (pmFPA *fpa, const pmFPAview *view, bool status);
 
 // Functions the check the data_exists flags
Index: /branches/czw_branch/20101203/psModules/src/camera/pmFPAfile.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/camera/pmFPAfile.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/camera/pmFPAfile.c	(revision 30118)
@@ -36,5 +36,5 @@
         return;
     }
-    psTrace ("pmFPAfileFree", 5, "freeing %s %ld\n", file->name,(psU64) file->fits);
+    psTrace ("pmFPAfileFree", 5, "freeing %s %p\n", file->name, file->fits);
     psAssert(!fpaFileFreeStrict || file->fits == NULL, "File %s wasn't closed.", file->name);
 
Index: /branches/czw_branch/20101203/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/camera/pmFPAfileIO.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/camera/pmFPAfileIO.c	(revision 30118)
@@ -135,7 +135,4 @@
     PS_ASSERT_PTR_NON_NULL(view, false);
 
-    // an internal file should not be sent here (should not be left on config->files)
-    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
-
     // skip the following states
     if (file->state & PM_FPA_STATE_INACTIVE) {
@@ -143,4 +140,8 @@
         return true;
     }
+
+    // an active internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
     if (file->mode != PM_FPA_MODE_READ) {
         psTrace("psModules.camera", 6, "skip read for %s, mode is not READ", file->name);
@@ -258,11 +259,12 @@
         return true;
     }
+
+    // an active internal file should not be returned to here
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
     if (file->mode != PM_FPA_MODE_WRITE) {
         psTrace("psModules.camera", 6, "skip create for non-write file %s", file->name);
         return true;
     }
-
-    // an internal file should not be returned to here
-    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
 
     // get the current level
@@ -335,13 +337,10 @@
     }
 
+    // an ACTIVE internal file should not be sent here
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
     if (file->mode != PM_FPA_MODE_WRITE) {
         psTrace("psModules.camera", 6, "skip write for %s, mode is not WRITE", file->name);
         return true;
-    }
-
-    // an internal file should not be returned to here
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
     }
 
@@ -523,7 +522,4 @@
     PS_ASSERT_PTR_NON_NULL(view, false);
 
-    // an internal file should not be sent here (should not be left on config->files)
-    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
-
     // skip the following states
     if (file->state & PM_FPA_STATE_INACTIVE) {
@@ -531,8 +527,12 @@
         return true;
     }
+
     if (file->state == PM_FPA_STATE_CLOSED) {
         psTrace("psModules.camera", 6, "skip close for %s, files is closed", file->name);
         return true;
     }
+
+    // an active internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
 
     // is current level == open level?
@@ -596,11 +596,11 @@
     PS_ASSERT_PTR_NON_NULL(view, false);
 
-    // an internal file should not be sent here (should not be left on config->files)
-    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
-
     if (file->state & PM_FPA_STATE_INACTIVE) {
         psTrace("psModules.camera", 6, "skip free for %s, files is inactive", file->name);
         return true;
     }
+
+    // an active internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
 
     // get the current level
@@ -746,5 +746,5 @@
     }
 
-    // these are programming errors
+    // an ACTIVE internal file should not be sent here
     PS_ASSERT(file->mode != PM_FPA_MODE_NONE, false);
     PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
Index: /branches/czw_branch/20101203/psModules/src/concepts/pmConceptsAverage.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/concepts/pmConceptsAverage.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/concepts/pmConceptsAverage.c	(revision 30118)
@@ -136,4 +136,51 @@
     return average;
 }
+float medianWithDropouts (psList *sources, char *name) {
+
+    bool status;
+
+    psListIterator *sourcesIter = psListIteratorAlloc(sources, PS_LIST_HEAD, false); // Iterator for sources
+    pmCell *cell = NULL;                // Source cell from iteration
+
+    psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+    psVector *values = psVectorAlloc(sources->n, PS_TYPE_F32);
+    int nvalues = 0;
+    while ((cell = psListGetAndIncrement(sourcesIter))) {
+        if (!cell) {
+            continue;
+        }
+
+        float value = psMetadataLookupF32(&status, cell->concepts, name);
+        if (!status) continue;
+        if (!isfinite(value)) continue;
+
+        values->data.F32[nvalues++] = value;
+    }
+    psFree (sourcesIter);
+    if (!nvalues) {
+        psWarning("no valid values found for %s\n", name);
+        psFree(values);
+        psFree(stats);
+        return INFINITY;
+    }
+    if (!(values = psVectorRealloc(values, nvalues))) {
+        psWarning("failed to reallocate values vector for %s\n", name);
+        psFree(stats);
+        return INFINITY;
+    }
+    if (!psVectorStats(stats, values, NULL, NULL, 0)) {
+        psWarning("psVectorStats failed for %s\n", name);
+        psFree(values);
+        psFree(stats);
+        return INFINITY;
+    }
+
+    psF32 median = psStatsGetValue(stats, PS_STAT_SAMPLE_MEDIAN);
+
+    psFree(values);
+    psFree(stats);
+
+    return median;
+}
 
 // Set a variety of concepts in a cell by averaging over several
@@ -145,5 +192,4 @@
     PS_ASSERT_INT_POSITIVE(sources->n, false);
 
-    float saturation = INFINITY;        // Saturation level
     float bad        = -INFINITY;       // Bad level
     double time      = 0.0;             // Time of observation
@@ -158,4 +204,5 @@
     float exposure  = averageWithDropouts (sources, "CELL.EXPOSURE");
     float darktime  = averageWithDropouts (sources, "CELL.DARKTIME");
+    float saturation = medianWithDropouts(sources, "CELL.SATURATION");
 
     // other concepts are a bit more "special"
@@ -221,13 +268,4 @@
         }
 
-        float cellSaturation = psMetadataLookupF32(NULL, cell->concepts, "CELL.SATURATION");
-	if (cellSaturation > 10000) {
-	    // do not allow invalid values to polute this calculation
-	    // XXX really need to do this on the basis of the fraction of the cell that contributes..
-	    // if a cell is completely masked, it should not be included.
-	    if (cellSaturation < saturation) {
-		saturation = cellSaturation;
-	    }
-	}
         float cellBad = psMetadataLookupF32(NULL, cell->concepts, "CELL.BAD");
         if (cellBad > bad) {
Index: /branches/czw_branch/20101203/psModules/src/config/pmConfigDump.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/config/pmConfigDump.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/config/pmConfigDump.c	(revision 30118)
@@ -150,5 +150,12 @@
     }
 
-    if (!psMetadataConfigWrite(config->user, resolved)) {
+    // check for Metadata compression options:
+    char *compressMode = NULL;
+    bool status = false;
+    if (config->camera) {
+	compressMode = psMetadataLookupStr(&status, config->camera, "METADATA.COMPRESSION");
+    }
+
+    if (!psMetadataConfigWrite(config->user, resolved, compressMode)) {
         psError(psErrorCodeLast(), false, "Unable to dump configuration to %s", filename);
         psFree(resolved);
Index: /branches/czw_branch/20101203/psModules/src/detrend/pmNonLinear.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/detrend/pmNonLinear.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/detrend/pmNonLinear.c	(revision 30118)
@@ -332,7 +332,4 @@
 	return(0.0);
     }
-/*     if (flux > correction_fluxes->data.F32[bin]) { */
-/* 	return(0.0); */
-/*     } */
   
     for (int i = 0; i < correction_fluxes->n - 1; i++) {
@@ -347,16 +344,7 @@
     }
 
-/*   PS_BIN_FOR_VALUE(bin,correction_fluxes,flux); */
-/*   if ((bin < 0)||(bin > correction_fluxes->n)) { */
-/*     return(1.0); */
-/*   } */
-  
-/*   PS_BIN_INTERPOLATE(result,correction_fluxes,correction_factors,bin,flux); */
     if (!isfinite(result)) {
 	result = 0.0;
     }
-/*     if (result <= 0) { */
-/* 	result = 1.0; */
-/*     } */
     return(result);
 }
@@ -372,7 +360,4 @@
 	return(0.0);
     }
-/*     if (flux > correction_fluxes->data.F32[bin]) { */
-/* 	return(0.0); */
-/*     } */
 
     for (int i = 0; i < correction_fluxes->n - 1; i++) {
@@ -389,19 +374,7 @@
     }
 
-/*   PS_BIN_FOR_VALUE(bin,correction_fluxes,flux); */
-/*   if ((bin < 0)||(bin > correction_fluxes->n)) { */
-/*     return(1.0); */
-/*   } */
-  
-/*   PS_BIN_INTERPOLATE(result,correction_fluxes,correction_factors,bin,flux); */
     if (!isfinite(result)) {
 	result = 0.0;
     }
-/*     if (result <= 0) { */
-/* 	result = 1.0; */
-/*     } */
     return(result);
 }
-
-  
-  
Index: /branches/czw_branch/20101203/psModules/src/objects/pmPSF_IO.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmPSF_IO.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmPSF_IO.c	(revision 30118)
@@ -62,4 +62,6 @@
 #include "pmSourceIO.h"
 
+bool pmPSFmodelReadPSFClump (psMetadata *analysis, psMetadata *header);
+
 bool pmPSFmodelCheckDataStatusForView (const pmFPAview *view, const pmFPAfile *file)
 {
@@ -851,65 +853,13 @@
 
     // read the psf clump data for each region
+    status = false;
     if (roAnalysis) {
-        int nRegions = psMetadataLookupS32 (&status, header, "PSF_CLN");
-        if (!status) {
-            // read old-style psf clump data
-
-            char regionName[64];
-            snprintf (regionName, 64, "PSF.CLUMP.REGION.000");
-            psMetadataAddS32 (roAnalysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 1);
-
-            psMetadata *regionMD = psMetadataLookupPtr (&status, roAnalysis, regionName);
-            if (!regionMD) {
-                regionMD = psMetadataAlloc();
-                psMetadataAddMetadata (roAnalysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
-                psFree (regionMD);
-            }
-
-            // psf clump data
-            pmPSFClump psfClump;
-
-            psfClump.X  = psMetadataLookupF32 (&status, header, "PSF_CLX" );  assert(status);
-            psfClump.Y  = psMetadataLookupF32 (&status, header, "PSF_CLY" );  assert(status);
-            psfClump.dX = psMetadataLookupF32 (&status, header, "PSF_CLDX");  assert(status);
-            psfClump.dY = psMetadataLookupF32 (&status, header, "PSF_CLDY");  assert(status);
-
-            psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
-            psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
-            psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
-            psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
-        } else {
-            psMetadataAddS32 (roAnalysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", nRegions);
-
-            for (int i = 0; i < nRegions; i++) {
-                char key[10];
-                char regionName[64];
-                snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
-
-                psMetadata *regionMD = psMetadataLookupPtr (&status, roAnalysis, regionName);
-                if (!regionMD) {
-                    regionMD = psMetadataAlloc();
-                    psMetadataAddMetadata (roAnalysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
-                    psFree (regionMD);
-                }
-
-                // psf clump data
-                pmPSFClump psfClump;
-
-                snprintf (key, 9, "CLX_%03d", i);
-                psfClump.X  = psMetadataLookupF32 (&status, header, key);  assert(status);
-                snprintf (key, 9, "CLY_%03d", i);
-                psfClump.Y  = psMetadataLookupF32 (&status, header, key);  assert(status);
-                snprintf (key, 9, "CLDX_%03d", i);
-                psfClump.dX = psMetadataLookupF32 (&status, header, key);  assert(status);
-                snprintf (key, 9, "CLDY_%03d", i);
-                psfClump.dY = psMetadataLookupF32 (&status, header, key);  assert(status);
-
-                psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
-                psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
-                psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
-                psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
-            }
-        }
+	status = pmPSFmodelReadPSFClump (roAnalysis, header);
+	if (!status) {
+	    psMetadataAddS32 (roAnalysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 0);
+	}
+    } 
+    if (!roAnalysis || !status) {
+	psWarning ("no PSF.CLUMP data available for PSF model");
     }
 
@@ -1123,3 +1073,66 @@
 }
 
-// XXX pmPSF to/from Metadata functions were defined for 1.22 and earlier, but were dropped
+bool pmPSFmodelReadPSFClump (psMetadata *analysis, psMetadata *header) {
+
+    bool status = false;;
+
+    int nRegions = psMetadataLookupS32 (&status, header, "PSF_CLN");
+    if (!status) {
+	// read old-style psf clump data
+
+	char regionName[64];
+	snprintf (regionName, 64, "PSF.CLUMP.REGION.000");
+	psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
+
+	if (!regionMD) {
+	    regionMD = psMetadataAlloc();
+	    psMetadataAddMetadata (analysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
+	    psFree (regionMD);
+	}
+
+	// psf clump data
+	pmPSFClump psfClump;
+	psfClump.X  = psMetadataLookupF32 (&status, header, "PSF_CLX" );  if (!status) return false;
+	psfClump.Y  = psMetadataLookupF32 (&status, header, "PSF_CLY" );  if (!status) return false;
+	psfClump.dX = psMetadataLookupF32 (&status, header, "PSF_CLDX");  if (!status) return false;
+	psfClump.dY = psMetadataLookupF32 (&status, header, "PSF_CLDY");  if (!status) return false;
+
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
+	psMetadataAddS32 (analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 1);
+    } else {
+	for (int i = 0; i < nRegions; i++) {
+	    char key[10];
+	    char regionName[64];
+	    snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
+
+	    psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName);
+	    if (!regionMD) {
+		regionMD = psMetadataAlloc();
+		psMetadataAddMetadata (analysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
+		psFree (regionMD);
+	    }
+
+	    // psf clump data
+	    pmPSFClump psfClump;
+
+	    snprintf (key, 9, "CLX_%03d", i);
+	    psfClump.X  = psMetadataLookupF32 (&status, header, key);  if (!status) return false;
+	    snprintf (key, 9, "CLY_%03d", i);
+	    psfClump.Y  = psMetadataLookupF32 (&status, header, key);  if (!status) return false;
+	    snprintf (key, 9, "CLDX_%03d", i);
+	    psfClump.dX = psMetadataLookupF32 (&status, header, key);  if (!status) return false;
+	    snprintf (key, 9, "CLDY_%03d", i);
+	    psfClump.dY = psMetadataLookupF32 (&status, header, key);  if (!status) return false;
+
+	    psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
+	    psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
+	    psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
+	    psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
+	}
+	psMetadataAddS32 (analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", nRegions);
+    }
+    return true;
+}
Index: /branches/czw_branch/20101203/psModules/src/objects/pmPSFtry.h
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmPSFtry.h	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmPSFtry.h	(revision 30118)
@@ -100,5 +100,5 @@
 bool pmPSFtryFitEXT (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal);
 
-bool pmPSFtryMakePSF (pmPSFtry *psfTry);
+bool pmPSFtryMakePSF (bool *pGoodFit, pmPSFtry *psfTry);
 
 bool pmPSFtryFitPSF (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal);
@@ -123,5 +123,5 @@
 );
 
-bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask);
+bool pmPSFFitShapeParams (bool *pGoodFit, pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask);
 
 float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction);
Index: /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryMakePSF.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryMakePSF.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryMakePSF.c	(revision 30118)
@@ -50,5 +50,5 @@
 Note: some of the array entries may be NULL (failed fits); ignore them.
  *****************************************************************************/
-bool pmPSFtryMakePSF (pmPSFtry *psfTry)
+bool pmPSFtryMakePSF (bool *pGoodFit, pmPSFtry *psfTry)
 {
     PS_ASSERT_PTR_NON_NULL(psfTry, false);
@@ -74,8 +74,14 @@
 
     // fit the shape parameters (SXX, SYY, SXY) as a function of position
-    if (!pmPSFFitShapeParams (psf, psfTry->sources, x, y, srcMask)) {
+    if (!pmPSFFitShapeParams (pGoodFit, psf, psfTry->sources, x, y, srcMask)) {
         psFree(x);
         psFree(y);
         return false;
+    }
+    if (!*pGoodFit) {
+	psWarning ("poor fit to PSF shape parameters for trend order %d, %d, skipping\n", psf->trendNx, psf->trendNy);
+	psFree(x);
+	psFree(y);
+	return true;
     }
 
@@ -115,5 +121,5 @@
         // the mask is carried from previous steps and updated with this operation
         // the weight is either the flux error or NULL, depending on 'psf->poissonErrorParams'
-        if (!pmTrend2DFit (trend, srcMask, 0xff, x, y, z, NULL)) {
+        if (!pmTrend2DFit (pGoodFit, trend, srcMask, 0xff, x, y, z, NULL)) {
             psError(PS_ERR_UNKNOWN, false, "failed to build psf model for parameter %d", i);
             psFree(x);
@@ -122,4 +128,13 @@
             return false;
         }
+	if (!*pGoodFit) {
+	    // if we do not get a good fit (but do not actually hit an error), 
+	    // tell the calling program to try something else
+	    psWarning ("poor fit to PSF parameter %d for trend order %d, %d, skipping\n", i, psf->trendNx, psf->trendNy);
+            psFree(x);
+            psFree(y);
+            psFree(z);
+            return true;
+	}
 	if (trend->mode == PM_TREND_MAP) {
 	    // p_psImagePrint (2, trend->map->map, "param N Before"); // XXX TEST:
@@ -139,4 +154,12 @@
 
             pmModel *modelPSF = pmModelFromPSF (source->modelEXT, psf);
+            if (!modelPSF) {
+                fprintf(f, "modelPSF is NULL\n");
+                break;
+            }
+            if (!source->modelEXT) {
+                fprintf(f, "source->modelEXT is NULL\n");
+                break;
+            }
 
             fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[PM_PAR_XPOS], source->modelEXT->params->data.F32[PM_PAR_YPOS]);
@@ -163,5 +186,5 @@
 
 // fit the shape parameters using the supplied order (pmPSF->trendNx,trendNy)
-bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask) {
+bool pmPSFFitShapeParams (bool *pGoodFit, pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask) {
 
     // we are doing a robust fit.  after each pass, we drop points which are more deviant than
@@ -219,5 +242,11 @@
 	trend = psf->params->data[PM_PAR_E0];
 	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
-	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e0, NULL);
+	status &= pmTrend2DFit (pGoodFit, trend, srcMask, 0xff, x, y, e0, NULL);
+	if (!*pGoodFit) {
+	    psFree (e0);
+	    psFree (e1);
+	    psFree (e2);
+	    return true;
+	}
 	mean = psStatsGetValue (trend->stats, meanOption);
 	stdev = psStatsGetValue (trend->stats, stdevOption);
@@ -228,5 +257,11 @@
 	trend = psf->params->data[PM_PAR_E1];
 	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
-	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e1, NULL);
+	status &= pmTrend2DFit (pGoodFit, trend, srcMask, 0xff, x, y, e1, NULL);
+	if (!*pGoodFit) {
+	    psFree (e0);
+	    psFree (e1);
+	    psFree (e2);
+	    return true;
+	}
 	mean = psStatsGetValue (trend->stats, meanOption);
 	stdev = psStatsGetValue (trend->stats, stdevOption);
@@ -237,5 +272,11 @@
 	trend = psf->params->data[PM_PAR_E2];
 	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
-	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e2, NULL);
+	status &= pmTrend2DFit (pGoodFit, trend, srcMask, 0xff, x, y, e2, NULL);
+	if (!*pGoodFit) {
+	    psFree (e0);
+	    psFree (e1);
+	    psFree (e2);
+	    return true;
+	}
 	mean = psStatsGetValue (trend->stats, meanOption);
 	stdev = psStatsGetValue (trend->stats, stdevOption);
@@ -246,4 +287,7 @@
 	if (!status) {
 	    psError (PS_ERR_UNKNOWN, true, "failed to fit PSF shape params");
+	    psFree (e0);
+	    psFree (e1);
+	    psFree (e2);
 	    return false;
 	}
Index: /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryModel.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryModel.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmPSFtryModel.c	(revision 30118)
@@ -136,9 +136,14 @@
 
         // stage 2: construct a psf (pmPSF) from this collection of model fits, including the 2D variation
-        if (!pmPSFtryMakePSF (psfTry)) {
+	bool goodFit = false;
+        if (!pmPSFtryMakePSF (&goodFit, psfTry)) {
             psError(PS_ERR_UNKNOWN, false, "failed to construct a psf model from collection of sources");
             psFree(psfTry);
             return NULL;
         }
+	if (!goodFit) {
+	    psWarning ("poor psf fit for order %d, skipping\n", i);
+	    continue;
+	}
 
         // stage 3: refit with fixed shape parameters, measure pmPSFtry->metric
@@ -169,4 +174,10 @@
     }
     psFree (srcMask);
+
+    if (!minPSF) {
+	psError(PS_ERR_UNKNOWN, false, "failed to construct a valid psf model from the sources");
+	psFree(psfTry);
+	return NULL;
+    }
 
     // keep the ones matching the min systematic error:
Index: /branches/czw_branch/20101203/psModules/src/objects/pmSource.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmSource.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmSource.c	(revision 30118)
@@ -189,6 +189,6 @@
     // pixels.  Modifying these pixels (ie, subtracting the model) will affect the pixels seen
     // by all copies.
-    source->pixels   = psImageCopyView(NULL, in->pixels);
-    source->variance   = psImageCopyView(NULL, in->variance);
+    source->pixels   = in->pixels   ? psImageCopyView(NULL, in->pixels)   : NULL;
+    source->variance = in->variance ? psImageCopyView(NULL, in->variance) : NULL;
     source->maskView = in->maskView ? psImageCopyView(NULL, in->maskView) : NULL;
 
Index: /branches/czw_branch/20101203/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmSourcePhotometry.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmSourcePhotometry.c	(revision 30118)
@@ -107,5 +107,5 @@
     // XXX handle negative flux, low-significance
     if (model->dparams->data.F32[PM_PAR_I0] > 0) {
-        SN = model->params->data.F32[PM_PAR_I0] / model->dparams->data.F32[PM_PAR_I0];
+        SN = fabs(model->params->data.F32[PM_PAR_I0] / model->dparams->data.F32[PM_PAR_I0]);
         source->errMag = 1.0 / SN;
     } else {
@@ -331,5 +331,5 @@
     }
     if (apFluxOut) *apFluxOut = apFlux;
-    if (apFluxErr) *apFluxErr = sqrt(apFluxVar);
+    if (apFluxErr) *apFluxErr = sqrt(fabs(apFluxVar));
 
     if (apFlux <= 0) {
Index: /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.c
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.c	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.c	(revision 30118)
@@ -179,5 +179,5 @@
 }
 
-bool pmTrend2DFit(pmTrend2D *trend, psVector *mask, psVectorMaskType maskVal, const psVector *x,
+bool pmTrend2DFit(bool *pGoodFit, pmTrend2D *trend, psVector *mask, psVectorMaskType maskVal, const psVector *x,
                   const psVector *y, const psVector *f, const psVector *df)
 {
@@ -188,5 +188,13 @@
     PS_ASSERT_VECTOR_NON_NULL(f, false);
 
-    bool status;
+    bool status = false;
+    *pGoodFit = false;
+    // for the psImageMap fit, it is possible to have valid data but no valid solution for
+    // example, an isolated cell may not be reached from other cells, making the solution
+    // degenerate.  psImageMapFit should probably handle this case, but until it does, we allow
+    // it to fail on the result, but not yield an error (pGoodFit = false).
+    // psVectorClipFitPolynomial2D can not fail in this way (really?), so pGoodFit is always
+    // true
+
     switch (trend->mode) {
       case PM_TREND_POLY_ORD:
@@ -196,4 +204,5 @@
         // of points in the image, and potentially based on the fractional range of the
         // data?
+	*pGoodFit = true;
         break;
 
@@ -201,5 +210,5 @@
         // XXX supply fraction from trend elements
         // XXX need to add the API which adjusts the scale
-        status = psImageMapClipFit(trend->map, trend->stats, mask, maskVal, x, y, f, df);
+        status = psImageMapClipFit(pGoodFit, trend->map, trend->stats, mask, maskVal, x, y, f, df);
         break;
 
Index: /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.h
===================================================================
--- /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.h	(revision 30117)
+++ /branches/czw_branch/20101203/psModules/src/objects/pmTrend2D.h	(revision 30118)
@@ -76,5 +76,6 @@
     );
 
-bool pmTrend2DFit(pmTrend2D *trend,
+bool pmTrend2DFit(bool *goodFit,
+		  pmTrend2D *trend,
                   psVector *mask,       // Warning: mask is modified!
                   psVectorMaskType maskVal,
Index: /branches/czw_branch/20101203/psphot/src/Makefile.am
===================================================================
--- /branches/czw_branch/20101203/psphot/src/Makefile.am	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/Makefile.am	(revision 30118)
@@ -103,16 +103,4 @@
 	psphotCleanup.c
 
-
-
-# # psphot analysis of the detectability of specified positions
-# psphotDetect_SOURCES =            \
-#         psphotDetect.c            \
-# 	psphotDetectArguments.c	  \
-# 	psphotDetectParseCamera.c \
-# 	psphotDetectImageLoop.c	  \
-# 	psphotDetectReadout.c	  \
-# 	psphotMosaicChip.c	  \
-# 	psphotCleanup.c
-
 # psphotTest_SOURCES = \
 #         psphotTest.c
@@ -137,4 +125,5 @@
 	psphotReadoutFindPSF.c	       \
 	psphotReadoutKnownSources.c    \
+	psphotReadoutForcedKnownSources.c    \
 	psphotReadoutMinimal.c	       \
 	psphotModelBackground.c	       \
Index: /branches/czw_branch/20101203/psphot/src/psphot.h
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphot.h	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphot.h	(revision 30118)
@@ -24,8 +24,9 @@
 bool            psphotModelTest (pmConfig *config, const pmFPAview *view, psMetadata *recipe);
 bool            psphotInit (void);
-bool            psphotReadout (pmConfig *config, const pmFPAview *view);
-bool            psphotReadoutFindPSF(pmConfig *config, const pmFPAview *view, psArray *inSources);
-bool            psphotReadoutKnownSources(pmConfig *config, const pmFPAview *view, psArray *inSources);
-bool            psphotReadoutMinimal(pmConfig *config, const pmFPAview *view);
+bool            psphotReadout (pmConfig *config, const pmFPAview *view, const char *filerule);
+bool            psphotReadoutFindPSF(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources);
+bool            psphotReadoutKnownSources(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources);
+bool            psphotReadoutForcedKnownSources(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources);
+bool            psphotReadoutMinimal(pmConfig *config, const pmFPAview *view, const char *filerule);
 
 bool            psphotReadoutCleanup (pmConfig *config, const pmFPAview *view, const char *filerule);
@@ -219,5 +220,5 @@
 bool            psphotFitSummary (void);
 
-bool            psphotLoadPSF (pmConfig *config, const pmFPAview *view);
+bool            psphotLoadPSF (pmConfig *config, const pmFPAview *view, const char *filerule);
 bool            psphotLoadPSFReadout (pmConfig *config, const pmFPAview *view, const char *outFilename, const char *inFilename, int index);
 
@@ -304,9 +305,14 @@
 pmConfig *psphotForcedArguments(int argc, char **argv);
 bool psphotForcedImageLoop (pmConfig *config);
-bool psphotForcedReadout(pmConfig *config, const pmFPAview *view);
+bool psphotForcedReadout(pmConfig *config, const pmFPAview *view, const char *filerule);
 
 pmConfig *psphotMakePSFArguments(int argc, char **argv);
 bool psphotMakePSFImageLoop (pmConfig *config);
-bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view);
+bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view, const char *filerule);
+
+int psphotFileruleCount(const pmConfig *config, const char *filerule);
+
+bool psphotAddKnownSources (pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources);
+
 
 /**** psphotStack prototypes ****/
@@ -432,3 +438,5 @@
 pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
 
+bool psphotCleanInputs (pmConfig *config, const pmFPAview *view, const char *filerule);
+
 #endif
Index: /branches/czw_branch/20101203/psphot/src/psphotAddNoise.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotAddNoise.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotAddNoise.c	(revision 30118)
@@ -18,6 +18,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotApResid.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotApResid.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotApResid.c	(revision 30118)
@@ -13,6 +13,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
@@ -72,8 +71,8 @@
     if (!measureAptrend) {
         // save nan values since these were not calculated
-        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
-        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
-        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
-        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
+        psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_META_REPLACE, "aperture residual",   NAN);
+        psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_META_REPLACE, "ap residual scatter", NAN);
+        psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_META_REPLACE, "number of apresid stars", 0);
+        psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", NAN);
         return true;
     }
@@ -325,8 +324,8 @@
 
     // save results for later output
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth ? psf->growth->apLoss : NAN);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_META_REPLACE, "aperture residual",   psf->ApResid);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_META_REPLACE, "ap residual scatter", psf->dApResid);
+    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_META_REPLACE, "number of apresid stars", psf->nApResid);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", psf->growth ? psf->growth->apLoss : NAN);
 
     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
@@ -345,8 +344,8 @@
 escape:
     // save nan values since these were not calculated
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
-    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_META_REPLACE, "aperture residual",   NAN);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_META_REPLACE, "ap residual scatter", NAN);
+    psMetadataAddS32 (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_META_REPLACE, "number of apresid stars", 0);
+    psMetadataAddF32 (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_META_REPLACE, "aperture loss (mag)", NAN);
 
     psFree (xPos);
@@ -379,5 +378,12 @@
 
     // XXX test for errors here
-    if (!pmTrend2DFit (apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
+    bool goodFit = false;
+    if (!pmTrend2DFit (&goodFit, apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
+	// XXX this is probably a real error, and I should exit
+        psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
+        psFree (apTrend);
+        return NULL;
+    }
+    if (!goodFit) {
         psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
         psFree (apTrend);
Index: /branches/czw_branch/20101203/psphot/src/psphotBasicDeblend.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotBasicDeblend.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotBasicDeblend.c	(revision 30118)
@@ -4,8 +4,5 @@
 bool psphotBasicDeblend (pmConfig *config, const pmFPAview *view, const char *filerule)
 {
-    bool status = true;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotBlendFit.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotBlendFit.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotBlendFit.c	(revision 30118)
@@ -10,6 +10,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotChoosePSF.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotChoosePSF.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotChoosePSF.c	(revision 30118)
@@ -10,6 +10,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
@@ -250,5 +249,7 @@
         if (!try) {
             // No big deal --- we'll try another model
-            psErrorClear();
+            if (i < modelNames->n - 1) {
+                psErrorClear();
+            }
             continue;
         }
Index: /branches/czw_branch/20101203/psphot/src/psphotDeblendSatstars.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDeblendSatstars.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotDeblendSatstars.c	(revision 30118)
@@ -4,8 +4,5 @@
 bool psphotDeblendSatstars (pmConfig *config, const pmFPAview *view, const char *filerule)
 {
-    bool status = true;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: anches/czw_branch/20101203/psphot/src/psphotDetect.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetect.c	(revision 30117)
+++ 	(revision )
@@ -1,41 +1,0 @@
-# include "psphotDetect.h"
-
-static void usage (void) {
-    fprintf (stderr, "USAGE: psphotDetect [-mask image(s)] [-masklist masklist] [-psf psfmodel] [-points pointlist] (output)\n");
-    exit (PS_EXIT_CONFIG_ERROR);
-}
-
-int main (int argc, char **argv) {
-
-    psTimerStart ("complete");
-    pmErrorRegister();			// register psModule's error codes/messages
-    psphotInit();
-
-    // load command-line arguments, options, and system config data
-    pmConfig *config = psphotDetectArguments (argc, argv);
-    if (!config) {
-	psErrorStackPrint(stderr, "Error reading arguments\n");
-	usage ();
-    }
-
-    // load input data (config and images (signal, noise, mask)
-    if (!psphotDetectParseCamera (config)) {
-        psErrorStackPrint(stderr, "Error setting up the camera\n");
-        exit (psphotGetExitStatus());
-    }
-
-    // call psphot for each readout
-    if (!psphotDetectImageLoop (config)) {
-        psErrorStackPrint(stderr, "Error in the psphotDetect image loop\n");
-        exit (psphotGetExitStatus());
-    }
-
-    psLogMsg ("psphot", 3, "complete psphotDetect run: %f sec\n", psTimerMark ("complete"));
-
-    psErrorCode exit_status = psphotGetExitStatus();
-    psphotCleanup (config);
-    exit (exit_status);
-}
-
-// all functions which return to this level must raise one of the top-level error codes if they
-// exit with an error.  these error codes are used to specify the program exit status
Index: anches/czw_branch/20101203/psphot/src/psphotDetect.h
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetect.h	(revision 30117)
+++ 	(revision )
@@ -1,23 +1,0 @@
-# ifdef HAVE_CONFIG_H
-# include <config.h>
-# endif
-
-#ifndef PSPHOT_DETECT_H
-#define PSPHOT_DETECT_H
-
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include "psphot.h"
-
-// Top level functions
-pmConfig   *psphotDetectArguments(int argc, char **argv);
-bool        psphotDetectParseCamera (pmConfig *config);
-bool        psphotDetectImageLoop (pmConfig *config);
-bool        psphotDetectReadout(pmConfig *config, const pmFPAview *view);
-
-bool        psphotMosaicChip(pmConfig *config, const pmFPAview *view, char *outFile, char *inFile);
-void        psphotCleanup (pmConfig *config);
-psExit      psphotGetExitStatus (void);
-
-#endif
Index: anches/czw_branch/20101203/psphot/src/psphotDetectArguments.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetectArguments.c	(revision 30117)
+++ 	(revision )
@@ -1,57 +1,0 @@
-# include "psphotDetect.h"
-
-pmConfig *psphotDetectArguments(int argc, char **argv) {
-
-    int N;
-
-    if (argc == 1) {
-        psError(PSPHOT_ERR_ARGUMENTS, true, "Too few arguments: %d", argc);
-        return NULL;
-    }
-
-    if ((N = psArgumentGet (argc, argv, "-version"))) {
-        psString version;
-        version = psphotVersionLong();    fprintf (stdout, "%s\n", version); psFree (version);
-        version = psModulesVersionLong(); fprintf (stdout, "%s\n", version); psFree (version);
-        version = psLibVersionLong();     fprintf (stdout, "%s\n", version); psFree (version);
-        exit (0);
-    }
-
-    // load config data from default locations
-    pmConfig *config = pmConfigRead(&argc, argv, PSPHOT_RECIPE);
-    if (config == NULL) {
-        psError(PSPHOT_ERR_CONFIG, false, "Can't read site configuration");
-        return NULL;
-    }
-
-    // save the following additional recipe values based on command-line options
-    // these options override the PSPHOT recipe values loaded from recipe files
-    psMetadata *options = pmConfigRecipeOptions (config, PSPHOT_RECIPE);
-
-    // XXX add psphot thread arguments?
-
-    // all three of these input files are required: if not found, we will exit
-    if (!pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",   "-mask",    "-masklist")) {
-        psError(PSPHOT_ERR_ARGUMENTS, false, "mask image not supplied");
-        return NULL;
-    }
-    if (!pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf", "-psflist")) {
-        psError(PSPHOT_ERR_ARGUMENTS, false, "mask image not supplied");
-        return NULL;
-    }
-    if (!pmConfigFileSetsMD (config->arguments, &argc, argv, "POINTS", "-points",  "-pointslist")) {
-        psError(PSPHOT_ERR_ARGUMENTS, false, "mask image not supplied");
-        return NULL;
-    }
-
-    if (argc != 2) {
-        psError(PSPHOT_ERR_ARGUMENTS, true, "Expected to see one more argument; saw %d", argc - 1);
-        return NULL;
-    }
-
-    // output position is fixed
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[1]);
-
-    psTrace("psphot", 1, "Done with psphotDetectArguments...\n");
-    return (config);
-}
Index: anches/czw_branch/20101203/psphot/src/psphotDetectImageLoop.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetectImageLoop.c	(revision 30117)
+++ 	(revision )
@@ -1,97 +1,0 @@
-# include "psphotDetect.h"
-
-# define ESCAPE(MESSAGE) { \
-  psError(PSPHOT_ERR_DATA, false, MESSAGE); \
-  psFree (view); \
-  return false; \
-}
-
-bool psphotDetectImageLoop (pmConfig *config) {
-
-    bool status;
-    pmChip *chip;
-    pmCell *cell;
-    pmReadout *readout;
-
-    pmFPAfile *mask = psMetadataLookupPtr (&status, config->files, "PSPHOT.MASK");
-    if (!status) {
-	psError(PSPHOT_ERR_PROG, false, "Can't find input mask data!");
-	return false;
-    }
-    pmFPAfile *input = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
-    if (!status) {
-	psError(PSPHOT_ERR_PROG, false, "Can't find input data!");
-	return false;
-    }
-
-    pmFPAview *view = pmFPAviewAlloc (0);
-    
-    // files associated with the science image
-    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE ("failed input for fpa in psphot.");
-
-    // for psphot, we force data to be read at the chip level 
-    while ((chip = pmFPAviewNextChip (view, mask->fpa, 1)) != NULL) {
-        psLogMsg ("psphot", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
-        if (!chip->process || !chip->file_exists) { continue; }
-
-	// load just the input image data (image, mask, weight)
-	pmFPAfileActivate (config->files, false, NULL);
-	pmFPAfileActivate (config->files, true, "PSPHOT.MASK");
-	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE ("failed input for Chip in psphot.");
-
-	// mosaic the cells of a chip into a single contiguous (trimmed) chip
-        if (!psphotMosaicChip(config, view, "PSPHOT.INPUT", "PSPHOT.MASK")) ESCAPE ("Unable to mosaic chip.");
-
-	// try to load other supporting data (PSF, SRC, etc).
-	// do not re-load the mask three files
-	pmFPAfileActivate (config->files, true, NULL);
-	pmFPAfileActivate (config->files, false, "PSPHOT.MASK");
-	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE ("failed input for Chip in psphot.");
-
-	// re-activate files so they will be closed and freed below
-	pmFPAfileActivate (config->files, true, NULL);
-
-	// there is now only a single chip (multiple readouts?). loop over it and process
-	while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
-            psLogMsg ("psphot", 5, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
-
-	    // process each of the readouts
-	    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
-		psLogMsg ("psphot", 6, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
-		if (!readout->data_exists) { continue; }
-
-		// run the actual photometry analysis on this chip/cell/readout
-		if (!psphotDetectReadout (config, view)) {
-		    psError(psErrorCodeLast(), false, "failure in psphotDetectReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
-		    psFree (view);
-		    return false;
-		}
-	    }
-	}
-
-	// save output which is saved at the chip level
-	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE ("failed output for Chip in psphot.");
-    }
-    // save output which is saved at the fpa level
-    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE ("failed ouput for FPA in psphot.");
-
-    // fail if we failed to handle an error
-    if (psErrorCodeLast() != PS_ERR_NONE) psAbort ("failed to handle an error!");
-
-    psFree (view);
-    return true;
-}
-
-// I/O files related to psphot:
-// PSPHOT.INPUT   : input image file(s)
-// PSPHOT.RESID   : residual image
-// PSPHOT.OUTPUT  : output object tables (object)
-
-// PSPHOT.BACKSUB : background subtracted image
-// PSPHOT.BACKGND : background model (full-scale image?)
-// PSPHOT.BACKMDL : background model (binned image?)
-// PSPHOT.PSF     : sample PSF images
-
-// PSPHOT.MASK
-// PSPHOT.WEIGHT
-// 
Index: anches/czw_branch/20101203/psphot/src/psphotDetectParseCamera.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetectParseCamera.c	(revision 30117)
+++ 	(revision )
@@ -1,43 +1,0 @@
-# include "psphotDetect.h"
-
-// define the needed / desired I/O files
-bool psphotDetectParseCamera (pmConfig *config) {
-
-    bool status = false;
-
-    // if MASK or WEIGHT was supplied on command line, bind files to 'load'
-    // the mask and weight will be mosaicked with the image
-    pmFPAfile *mask = pmFPAfileDefineFromArgs (&status, config, "PSPHOT.MASK", "MASK");
-    if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
-        return NULL;
-    }
-    if (!psphotSetMaskBits (config)) {
-      // XXX shouldn't this come after the file has been read?
-        psError (PS_ERR_UNKNOWN, false, "failed to set mask bit values");
-        return NULL;
-    }
-    mask->dataLevel = PM_FPA_LEVEL_CHIP; // force load at the CHIP level
-
-    // the psphot analysis is performed on chips
-    pmFPAfile *input = pmFPAfileDefineChipMosaic(config, mask->fpa, "PSPHOT.INPUT");
-    if (!input) {
-        psError(PSPHOT_ERR_CONFIG, false, _("Unable to generate new file from PSPHOT.INPUT"));
-        return NULL;
-    }
-
-    // the PSF model is required
-    pmFPAfileBindFromArgs(&status, mask, config, "PSPHOT.PSF.LOAD", "PSPHOT.PSF");
-    if (!status) {
-      psError(PSPHOT_ERR_CONFIG, false, "Failed to find/build PSPHOT.PSF.LOAD");
-      return status;
-    }
-
-    if (!pmFPAfileDefineFromArgs (&status, config, "PSPHOT.INPUT.PTS", "POINTS")) {
-      psError(PSPHOT_ERR_CONFIG, false, "Failed to find/build PSPHOT.INPUT.PTS");
-      return status;
-    }
-
-    psErrorClear();                     // some metadata lookup may have failed
-    return true;
-}
Index: anches/czw_branch/20101203/psphot/src/psphotDetectReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotDetectReadout.c	(revision 30117)
+++ 	(revision )
@@ -1,54 +1,0 @@
-# include "psphotInternal.h"
-
-bool psphotDetectReadout(pmConfig *config, const pmFPAview *view) {
-
-    // measure the total elapsed time in psphotReadout.  XXX the current threading plan
-    // for psphot envisions threading within psphotReadout, not multiple threads calling
-    // the same psphotReadout.  In the current plan, this dtime is the elapsed time used
-    // jointly by the multiple threads, not the total time used by all threads.
-    psTimerStart ("psphotReadout");
-
-    // select the current recipe
-    psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
-    if (!recipe) {
-        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
-        return false;
-    }
-
-    // find the currently selected readout
-    pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
-    PS_ASSERT_PTR_NON_NULL (readout, false);
-
-    // Generate the mask and weight images, including the user-defined analysis region of interest
-    psphotSetMaskAndWeight (config, readout, recipe);
-
-    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved in the recipe
-    pmPSF *psf = psphotLoadPSF (config, view, recipe);
-    psAssert (psf, "psf should be loaded");
-
-    // grab the sources of interest from the storage location (pmFPAfile PSPHOT.INPUT.CMF)
-    psArray *sources = psphotLoadPSFSources (config, view);
-    if (!sources) {
-      psError(PS_ERR_UNKNOWN, false, "No sources supplied to measure PSF");
-      return false;
-    }
-
-    // include externally-supplied sources (supplied as PSPHOT.INPUT.CMF)
-    psphotSetSourceParams (config, sources, psf);
-
-    // calculate source magnitudes
-    psphotPSFWeights(config, readout, view, sources);
-
-    // create the exported-metadata and free local data
-    return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
-}
-
-// deep in pmSourcePixelWeight, we need the following items for each location of interest:
-// pmModel *model (should be a realized version of the PSF, can have unity normalization)
-// psImage *mask  (local subimage of mask for source)
-// psImageMaskType maskVal (from recipe & mask header)
-
-{ 
-    pmModel *model = pmModelFromPSFforXY (psf, x, y, 1.0);
-}
-
Index: /branches/czw_branch/20101203/psphot/src/psphotEfficiency.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotEfficiency.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotEfficiency.c	(revision 30118)
@@ -164,6 +164,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
Index: /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysis.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysis.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysis.c	(revision 30118)
@@ -22,6 +22,5 @@
     }
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysisByObject.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysisByObject.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceAnalysisByObject.c	(revision 30118)
@@ -41,6 +41,5 @@
 
     // number of images used to define sources
-    int nImages = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int nImages = psphotFileruleCount(config, filerule);
 
     // generate look-up arrays for readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceFits.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotExtendedSourceFits.c	(revision 30118)
@@ -16,6 +16,5 @@
     }
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotFindDetections.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotFindDetections.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotFindDetections.c	(revision 30118)
@@ -12,6 +12,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotFitSourcesLinear.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotFitSourcesLinear.c	(revision 30118)
@@ -21,6 +21,5 @@
     assert (recipe);
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotForcedImageLoop.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotForcedImageLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotForcedImageLoop.c	(revision 30118)
@@ -84,5 +84,5 @@
 
                 // run the actual photometry analysis on this chip/cell/readout
-                if (!psphotForcedReadout (config, view)) {
+                if (!psphotForcedReadout (config, view, "PSPHOT.INPUT")) {
                     psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
                     psFree (view);
Index: /branches/czw_branch/20101203/psphot/src/psphotForcedReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotForcedReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotForcedReadout.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotForcedReadout(pmConfig *config, const pmFPAview *view) {
+bool psphotForcedReadout(pmConfig *config, const pmFPAview *view, const char *filerule) {
 
     // measure the total elapsed time in psphotReadout.  XXX the current threading plan
@@ -20,5 +20,5 @@
 
     // set the photcode for this image
-    if (!psphotAddPhotcode (config, view, "PSPHOT.INPUT")) {
+    if (!psphotAddPhotcode (config, view, filerule)) {
         psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -30,38 +30,38 @@
 
     // Generate the mask and weight images, including the user-defined analysis region of interest
-    psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT");
+    psphotSetMaskAndVariance (config, view, filerule);
     if (!strcasecmp (breakPt, "NOTHING")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // generate a background model (median, smoothed image)
-    if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    if (!psphotModelBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
     }
-    if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    if (!psphotSubtractBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "BACKMDL")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
-    if (!psphotLoadPSF (config, view)) {
+    if (!psphotLoadPSF (config, view, filerule)) {
     	// this only happens if we had a programming error in psphotLoadPSF
         psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // include externally-supplied sources
-    psphotLoadExtSources (config, view, "PSPHOT.INPUT");
+    psphotLoadExtSources (config, view, filerule);
 
     // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
-    psphotGuessModels (config, view, "PSPHOT.INPUT");
+    psphotGuessModels (config, view, filerule);
 
     // merge the newly selected sources into the existing list
     // NOTE: merge OLD and NEW
-    psphotMergeSources (config, view, "PSPHOT.INPUT");
+    psphotMergeSources (config, view, filerule);
 
     // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", false);
+    psphotFitSourcesLinear (config, view, filerule, false);
 
     // identify CRs and extended sources
@@ -71,5 +71,5 @@
 
     // calculate source magnitudes
-    psphotMagnitudes(config, view, "PSPHOT.INPUT");
+    psphotMagnitudes(config, view, filerule);
 
     // XXX do I want to do this?
@@ -80,10 +80,10 @@
 
     // replace background in residual image
-    psphotSkyReplace (config, view, "PSPHOT.INPUT");
+    psphotSkyReplace (config, view, filerule);
 
     // drop the references to the image pixels held by each source
-    psphotSourceFreePixels (config, view, "PSPHOT.INPUT");
+    psphotSourceFreePixels (config, view, filerule);
 
     // create the exported-metadata and free local data
-    return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup (config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotGuessModels.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotGuessModels.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotGuessModels.c	(revision 30118)
@@ -12,6 +12,5 @@
     bool status = true;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
@@ -207,5 +206,5 @@
             float Xc = 0.5*readout->image->numCols;
             float Yc = 0.5*readout->image->numRows;
-            pmModel *modelPSF = pmModelFromPSFforXY(psf, Xc, Yc, Io);
+            modelPSF = pmModelFromPSFforXY(psf, Xc, Yc, Io);
             if (modelPSF == NULL) {
                 psError(PSPHOT_ERR_PSF, false, "Failed to determine PSF model at center of image");
Index: /branches/czw_branch/20101203/psphot/src/psphotImageLoop.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotImageLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotImageLoop.c	(revision 30118)
@@ -109,5 +109,5 @@
 
                 // run the actual photometry analysis on this chip/cell/readout
-                if (!psphotReadout (config, view)) {
+                if (!psphotReadout (config, view, "PSPHOT.INPUT")) {
                     psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
                     psFree (view);
Index: /branches/czw_branch/20101203/psphot/src/psphotImageQuality.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotImageQuality.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotImageQuality.c	(revision 30118)
@@ -13,6 +13,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
@@ -99,9 +98,9 @@
         // r^2 sin(2t) = r^2 2 cos t sin t = 2 x y
 
-        // r^2 cos(3t) = r^2 cos^3 t - r^2 3 cos t sin^2 t = (x^3 - 3 x y^2) / r
-        // r^2 sin(3t) = r^2 3 cos^2 t sin t - sin^3 t = (3 x^2 y - y^3) / r
-
-        // r^2 cos(4t) = r^2 cos^4 t - r^2 6 cos^2 t sin^2 t + r^2 sin^4 t = (x^4 - 6 x^2 y^2 + y^4) / r^2
-        // r^2 sin(4t) = r^2 4 cos^3 t sin t - 4 sin^3 t cos t = (4 x^3 y - 4 y^3 x) / r^2
+        // r^3 cos(3t) = r^3 cos^3 t - r^2 3 cos t sin^2 t = (x^3 - 3 x y^2)
+        // r^3 sin(3t) = r^3 3 cos^2 t sin t - sin^3 t = (3 x^2 y - y^3)
+
+        // r^4 cos(4t) = r^4 cos^4 t - r^2 6 cos^2 t sin^2 t + r^2 sin^4 t = (x^4 - 6 x^2 y^2 + y^4)
+        // r^4 sin(4t) = r^4 4 cos^3 t sin t - 4 sin^3 t cos t = (4 x^3 y - 4 y^3 x)
 
         num++;
Index: /branches/czw_branch/20101203/psphot/src/psphotLoadPSF.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotLoadPSF.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotLoadPSF.c	(revision 30118)
@@ -6,5 +6,5 @@
 
 // XXX for now (2010.01.27), the supporting programs do not define multiple PSPHOT.PSF.LOAD
-// files to go with multiple PSPHOT.INPUT files.  as a result, the implementation below is
+// files to go with multiple input files.  as a result, the implementation below is
 // currently going to work for the case of a single input file, but will fail if we try with a
 // stack of images.
@@ -59,11 +59,8 @@
 }
 
-bool psphotLoadPSF (pmConfig *config, const pmFPAview *view) {
+// PSPHOT.PSF.LOAD vs input file -- see note at top
+bool psphotLoadPSF (pmConfig *config, const pmFPAview *view, const char *filerule) {
 
-    bool status = false;
-
-    // XXX PSPHOT.PSF.LOAD vs PSPHOT.INPUT -- see note at top
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
@@ -71,5 +68,5 @@
 
         // Generate the mask and weight images, including the user-defined analysis region of interest
-        if (!psphotLoadPSFReadout (config, view, "PSPHOT.INPUT", "PSPHOT.PSF.LOAD", i)) {
+        if (!psphotLoadPSFReadout (config, view, filerule, "PSPHOT.PSF.LOAD", i)) {
             psError (PSPHOT_ERR_CONFIG, false, "failed to load PSF model for PSPHOT.PSF.LOAD entry %d", i);
             return false;
Index: /branches/czw_branch/20101203/psphot/src/psphotMagnitudes.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMagnitudes.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMagnitudes.c	(revision 30118)
@@ -9,6 +9,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
Index: /branches/czw_branch/20101203/psphot/src/psphotMakeFluxScale.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMakeFluxScale.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMakeFluxScale.c	(revision 30118)
@@ -55,6 +55,13 @@
     fPts->n = Npts;
 
-    if (!pmTrend2DFit (trend, NULL, 0xff, xPts, yPts, fPts, NULL)) {
+    // XXX we should allow the spatial sampling to decrease if the fit fails
+    bool goodFit = false;
+    if (!pmTrend2DFit (&goodFit, trend, NULL, 0xff, xPts, yPts, fPts, NULL)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to fit trend");
+        success = false;
+        goto DONE;
+    }
+    if (!goodFit) {
+        psError(PS_ERR_UNKNOWN, false, "poor fit to flux-scale trend");
         success = false;
         goto DONE;
Index: /branches/czw_branch/20101203/psphot/src/psphotMakePSFImageLoop.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMakePSFImageLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMakePSFImageLoop.c	(revision 30118)
@@ -84,5 +84,5 @@
 
                 // run the actual photometry analysis on this chip/cell/readout
-                if (!psphotMakePSFReadout (config, view)) {
+                if (!psphotMakePSFReadout (config, view, "PSPHOT.INPUT")) {
                     psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
                     psFree (view);
Index: /branches/czw_branch/20101203/psphot/src/psphotMakePSFReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMakePSFReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMakePSFReadout.c	(revision 30118)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view) {
+bool psphotMakePSFReadout(pmConfig *config, const pmFPAview *view, const char *filerule) {
 
     // measure the total elapsed time in psphotReadout.  XXX the current threading plan
@@ -19,5 +19,5 @@
 
     // set the photcode for this image
-    if (!psphotAddPhotcode (config, view, "PSPHOT.INPUT")) {
+    if (!psphotAddPhotcode (config, view, filerule)) {
         psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -29,21 +29,21 @@
 
     // Generate the mask and weight images, including the user-defined analysis region of interest
-    psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT");
+    psphotSetMaskAndVariance (config, view, filerule);
     if (!strcasecmp (breakPt, "NOTHING")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // generate a background model (median, smoothed image)
-    if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    if (!psphotModelBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
     }
-    if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    if (!psphotSubtractBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "BACKMDL")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
-    psphotLoadExtSources (config, view, "PSPHOT.INPUT");
+    psphotLoadExtSources (config, view, filerule);
 
     // If sources have been supplied, then these should be used to measure the PSF include
@@ -53,24 +53,24 @@
     // a text file have no valid SN values, but psphotChoosePSF needs to select the top
     // PSF_MAX_NSTARS to generate the PSF.
-    if (!psphotCheckExtSources (config, view, "PSPHOT.INPUT")) {
+    if (!psphotCheckExtSources (config, view, filerule)) {
 	psLogMsg ("psphot", 3, "failure to select possible PSF sources (external or internal)");
-	return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+	return psphotReadoutCleanup (config, view, filerule);
     }
 
     // Use bright stellar objects to measure PSF. If we do not have enough stars to generate
     // the PSF, build one from the SEEING guess and model class
-    if (!psphotChoosePSF (config, view, "PSPHOT.INPUT")) {
+    if (!psphotChoosePSF (config, view, filerule)) {
 	psLogMsg ("psphot", 3, "failure to construct a psf model");
-	return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+	return psphotReadoutCleanup (config, view, filerule);
     }
 
     // measure aperture photometry corrections
 # if 0
-    if (!psphotApResid (config, view, "PSPHOT.INPUT")) {
+    if (!psphotApResid (config, view, filerule)) {
         psLogMsg ("psphot", 3, "failed on psphotApResid");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 # endif
 
-    return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup (config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotMaskReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMaskReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMaskReadout.c	(revision 30118)
@@ -9,6 +9,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
@@ -17,5 +16,5 @@
 	// Generate the mask and weight images, including the user-defined analysis region of interest
 	if (!psphotSetMaskAndVarianceReadout (config, view, filerule, i, recipe)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to generate mask for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed to generate mask for %s entry %d", filerule, i);
 	    return false;
 	}
Index: /branches/czw_branch/20101203/psphot/src/psphotMergeSources.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotMergeSources.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotMergeSources.c	(revision 30118)
@@ -8,8 +8,5 @@
 bool psphotMergeSources (pmConfig *config, const pmFPAview *view, const char *filerule)
 {
-    bool status = true;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
@@ -70,5 +67,5 @@
 // XXX This function needs to be updated to loop over set of input files.  At the moment, we
 // only expect a single entry for PSPHOT.INPUT.CMF and PSPHOT.SOURCES.TEXT, so we can only
-// associate input sources with a single entry for PSPHOT.INPUT
+// associate input sources with a single entry for the filerule
 bool psphotLoadExtSources (pmConfig *config, const pmFPAview *view, const char *filerule) {
 
@@ -166,4 +163,69 @@
 }
 
+// copy the known sources (as external) to the detection list of the given filerule
+bool psphotAddKnownSources (pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources) {
+
+    bool status = false;
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
+
+    // determine properties (sky, moments) of initial sources
+    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
+    psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
+
+    // XXX this seems like an arbitrary number...
+    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
+
+    // find the currently selected readout 
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, 0); // File of interest
+    psAssert (file, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
+    if (!detections) {
+	detections = pmDetectionsAlloc();
+	detections->newSources = psArrayAllocEmpty (100);
+	// save detections on the readout->analysis
+	if (!psMetadataAddPtr (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "psphot detections", detections)) {
+	    psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
+	    return false;
+	}
+    } else {
+	psMemIncrRefCounter(detections); // so we can free the detections below
+    }
+
+    // copy the sources from inSources to the new detection structure
+    for (int i = 0; i < inSources->n; i++) {
+      pmSource *inSource = inSources->data[i];
+
+      pmSource *newSource = pmSourceCopy(inSource);
+      newSource->mode |= PM_SOURCE_MODE_EXTERNAL;
+      
+      // drop the loaded source modelPSF
+      psFree (newSource->modelPSF);
+      // source->modelPSF = NULL;  check this!
+
+      // drop the references to the original image pixels:
+      pmSourceFreePixels (newSource);
+
+      // allocate image, weight, mask for the new image for each peak (square of radius OUTER)
+      pmSourceDefinePixels (newSource, readout, newSource->peak->x, newSource->peak->y, OUTER);
+
+      newSource->imageID = 0;
+      // XXX reset the source ID? raised questions about the meaning of this ID...
+      // P_PM_SOURCE_SET_ID(source, i);
+
+      psArrayAdd (detections->newSources, 100, newSource);
+    }
+    psLogMsg ("psphot", 3, "%ld known sources supplied", detections->newSources->n);
+
+    psFree (detections);
+    return true;
+}
+
 // extract the input sources corresponding to this readout
 // XXX this function needs to be updated to work with the new context of psphot inputs
@@ -405,6 +467,5 @@
     bool status = true;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, ruleSrc);
 
     // skip the chisq image because it is a duplicate of the detection version
Index: /branches/czw_branch/20101203/psphot/src/psphotModelBackground.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotModelBackground.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotModelBackground.c	(revision 30118)
@@ -383,16 +383,12 @@
 }
 
-// XXX supply filename or keep PSPHOT.INPUT fixed?
 bool psphotModelBackground (pmConfig *config, const pmFPAview *view, const char *filerule)
 {
-    bool status = false;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
         if (!psphotModelBackgroundReadoutFileIndex(config, view, filerule, i)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to model background for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed to model background for %s entry %d", filerule, i);
             return false;
         }
Index: /branches/czw_branch/20101203/psphot/src/psphotOutput.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotOutput.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotOutput.c	(revision 30118)
@@ -1,3 +1,19 @@
 # include "psphotInternal.h"
+
+// convert filerule to filerule.NUM and look up in the config->arguments metadata
+int psphotFileruleCount(const pmConfig *config, const char *filerule) {
+
+    bool status = false;
+
+    psString name = NULL;
+    psStringAppend(&name, "%s.NUM", filerule);
+    int num = psMetadataLookupS32 (&status, config->arguments, name);
+    if (!status) {
+      // we only explicitly define (filerule.NUM) if we have more than 1
+      num = 1;
+    }
+    psFree (name);
+    return num;
+}
 
 pmReadout *psphotSelectBackground (pmConfig *config,
@@ -63,15 +79,4 @@
     fclose (f);
     return true;
-}
-
-// XXX replace this with a call to a pmConfig function (pmConfigDump...)
-bool psphotDumpConfig (pmConfig *config) {
-
-  psMetadataConfigWrite (config->user, "user.md");
-  psMetadataConfigWrite (config->camera, "camera.md");
-  psMetadataConfigWrite (config->recipes, "recipes.md");
-  psMetadataConfigWrite (config->arguments, "arguments.md");
-  psMetadataConfigWrite (config->files, "files.md");
-  return true;
 }
 
@@ -126,15 +131,42 @@
 }
 
+bool psphotCleanInputsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index);
+bool psphotCleanInputs (pmConfig *config, const pmFPAview *view, const char *filerule) {
+
+    int num = psphotFileruleCount(config, filerule);
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotCleanInputsReadout (config, view, filerule, i)) {
+	  psError (PSPHOT_ERR_CONFIG, false, "failed to clean inputs for %s entry %d", filerule, i);
+	    return false;
+	}
+    }
+    return true;
+}
+
+bool psphotCleanInputsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index) {
+
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
+    PS_ASSERT (file, false);
+
+    pmReadout  *readout = pmFPAviewThisReadout (view, file->fpa);
+
+    // XXX anything else to remove?
+    if (psMetadataLookup(readout->analysis, "PSPHOT.DETECTIONS")) {
+	psMetadataRemoveKey(readout->analysis, "PSPHOT.DETECTIONS");
+    }
+
+    return true;
+}
+
 bool psphotAddPhotcode (pmConfig *config, const pmFPAview *view, const char *filerule) {
 
-    bool status = false;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
 	if (!psphotAddPhotcodeReadout (config, view, filerule, i)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to add photcode to PSPHOT.INPUT entry %d", i);
+	  psError (PSPHOT_ERR_CONFIG, false, "failed to add photcode to %s entry %d", filerule, i);
 	    return false;
 	}
@@ -357,5 +389,5 @@
     // XXX need alternative output function
     // psMetadata *psfData = pmPSFtoMetadata (NULL, try->psf);
-    // psMetadataConfigWrite (psfData, "psfmodel.dat");
+    // psMetadataConfigWrite (psfData, "psfmodel.dat", NULL);
     psLogMsg ("psphot.choosePSF", PS_LOG_INFO, "wrote out psf-subtracted image, psf data, exiting\n");
 
Index: /branches/czw_branch/20101203/psphot/src/psphotParseCamera.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotParseCamera.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotParseCamera.c	(revision 30118)
@@ -39,6 +39,4 @@
         return NULL;
     }
-    // specify the number of psphot input images
-    psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
 
     // define the additional input/output files associated with psphot
Index: /branches/czw_branch/20101203/psphot/src/psphotRadialApertures.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotRadialApertures.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotRadialApertures.c	(revision 30118)
@@ -18,6 +18,5 @@
     }
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotRadialAperturesByObject.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotRadialAperturesByObject.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotRadialAperturesByObject.c	(revision 30118)
@@ -21,6 +21,5 @@
 
     // number of images used to define sources
-    int nImages = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int nImages = psphotFileruleCount(config, filerule);
 
     // radMax stores the upper bounds of the annuli
Index: /branches/czw_branch/20101203/psphot/src/psphotRadiusChecks.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotRadiusChecks.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotRadiusChecks.c	(revision 30118)
@@ -135,8 +135,5 @@
     EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
 
-    float skyMean  = psMetadataLookupF32 (&status, readout->analysis, "SKY_MEAN");
     float skyStdev = psMetadataLookupF32 (&status, readout->analysis, "SKY_STDEV");
-
-    fprintf (stderr, "sky: %f +/- %f\n", skyMean, skyStdev);
 
     EXT_FIT_SKY_SIG = skyStdev;
Index: /branches/czw_branch/20101203/psphot/src/psphotReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadout.c	(revision 30118)
@@ -9,5 +9,5 @@
 }
 
-bool psphotReadout(pmConfig *config, const pmFPAview *view) {
+bool psphotReadout(pmConfig *config, const pmFPAview *view, const char *filerule) {
 
     // measure the total elapsed time in psphotReadout.  dtime is the elapsed time used jointly
@@ -27,6 +27,12 @@
     psAssert (breakPt, "configuration error: set BREAK_POINT");
 
+    // remove cruft from the input analysis structure
+    if (!psphotCleanInputs (config, view, filerule)) {
+        psError (PSPHOT_ERR_PROG, false, "trouble setting up the inputs");
+        return false;
+    }
+
     // set the photcode for this image
-    if (!psphotAddPhotcode (config, view, "PSPHOT.INPUT")) {
+    if (!psphotAddPhotcode (config, view, filerule)) {
         psError (PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -34,102 +40,101 @@
 
     // Generate the mask and weight images, including the user-defined analysis region of interest
-    if (!psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup(config, view, "PSPHOT.INPUT");
+    if (!psphotSetMaskAndVariance (config, view, filerule)) {
+        return psphotReadoutCleanup(config, view, filerule);
     }
     if (!strcasecmp (breakPt, "NOTHING")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // generate a background model (median, smoothed image)
-    if (!psphotModelBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
-    }
-
-    if (!psphotSubtractBackground (config, view, "PSPHOT.INPUT")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    if (!psphotModelBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
+    }
+
+    if (!psphotSubtractBackground (config, view, filerule)) {
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "BACKMDL")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // load the psf model, if suppled.  FWHM_MAJ,FWHM_MIN,etc are determined and saved on
-    // readout->analysis. XXX Note: this function currently only works with a single
-    // PSPHOT.INPUT
-    if (!psphotLoadPSF (config, view)) { // ??? need to supply 2 ?
+    // readout->analysis. NOTE: this function currently only loads from PSPHOT.PSF.LOAD
+    if (!psphotLoadPSF (config, view, filerule)) { // ??? need to supply 2 ?
         psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // find the detections (by peak and/or footprint) in the image.
-    if (!psphotFindDetections (config, view, "PSPHOT.INPUT", true)) { // pass 1
+    if (!psphotFindDetections (config, view, filerule, true)) { // pass 1
         // this only happens if we had an error in psphotFindDetections
         psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct sources and measure basic stats (saved on detections->newSources)
-    if (!psphotSourceStats (config, view, "PSPHOT.INPUT", true)) { // pass 1
+    if (!psphotSourceStats (config, view, filerule, true)) { // pass 1
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "PEAKS")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // find blended neighbors of very saturated stars (detections->newSources)
-    if (!psphotDeblendSatstars (config, view, "PSPHOT.INPUT")) {
+    if (!psphotDeblendSatstars (config, view, filerule)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failed on satstar deblend analysis");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // mark blended peaks PS_SOURCE_BLEND (detections->newSources)
-    if (!psphotBasicDeblend (config, view, "PSPHOT.INPUT")) {
+    if (!psphotBasicDeblend (config, view, filerule)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failed on deblend analysis");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // classify sources based on moments, brightness.  if a PSF model has been loaded, the PSF
     // clump defined for it is used not measured (detections->newSources)
-    if (!psphotRoughClass (config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotRoughClass (config, view, filerule)) { // pass 1
         psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough classifications");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // if we were not supplied a PSF model, determine the IQ stats here (detections->newSources)
-    if (!psphotImageQuality (config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotImageQuality (config, view, filerule)) { // pass 1
         psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "MOMENTS")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // use bright stellar objects to measure PSF if we were supplied a PSF for any input file,
     // this step is skipped
-    if (!psphotChoosePSF (config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotChoosePSF (config, view, filerule)) { // pass 1
         psLogMsg ("psphot", 3, "failure to construct a psf model");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
     if (!strcasecmp (breakPt, "PSFMODEL")) {
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // include externally-supplied sources
     // XXX fix this in the new multi-input context
-    // psphotLoadExtSources (config, view, "PSPHOT.INPUT"); // pass 1
+    // psphotLoadExtSources (config, view, filerule); // pass 1
 
     // construct an initial model for each object, set the radius to fitRadius, set circular
     // fit mask (detections->newSources)
-    psphotGuessModels (config, view, "PSPHOT.INPUT"); // pass 1
+    psphotGuessModels (config, view, filerule); // pass 1
 
     // merge the newly selected sources into the existing list
     // NOTE: merge OLD and NEW
-    psphotMergeSources (config, view, "PSPHOT.INPUT");
+    psphotMergeSources (config, view, filerule);
 
     // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", false); // pass 1 (detections->allSources)
+    psphotFitSourcesLinear (config, view, filerule, false); // pass 1 (detections->allSources)
 
     // identify CRs and extended sources (only unmeasured sources are measured)
-    psphotSourceSize (config, view, "PSPHOT.INPUT", true); // pass 1 (detections->allSources)
+    psphotSourceSize (config, view, filerule, true); // pass 1 (detections->allSources)
     if (!strcasecmp (breakPt, "ENSEMBLE")) {
         goto finish;
@@ -138,12 +143,12 @@
     // non-linear PSF and EXT fit to brighter sources
     // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
-    psphotBlendFit (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
+    psphotBlendFit (config, view, filerule); // pass 1 (detections->allSources)
 
     // replace all sources
-    psphotReplaceAllSources (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
+    psphotReplaceAllSources (config, view, filerule); // pass 1 (detections->allSources)
 
     // linear fit to include all sources (subtract again)
     // NOTE : apply to ALL sources (extended + psf)
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", true); // pass 2 (detections->allSources)
+    psphotFitSourcesLinear (config, view, filerule, true); // pass 2 (detections->allSources)
 
     // if we only do one pass, skip to extended source analysis
@@ -153,40 +158,40 @@
 
     // add noise for subtracted objects
-    psphotAddNoise (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
+    psphotAddNoise (config, view, filerule); // pass 1 (detections->allSources)
 
     // find fainter sources
     // NOTE: finds new peaks and new footprints, OLD and FULL set are saved on detections
-    psphotFindDetections (config, view, "PSPHOT.INPUT", false); // pass 2 (detections->peaks, detections->footprints)
+    psphotFindDetections (config, view, filerule, false); // pass 2 (detections->peaks, detections->footprints)
 
     // remove noise for subtracted objects (ie, return to normal noise level)
     // NOTE: this needs to operate only on the OLD sources
-    psphotSubNoise (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
+    psphotSubNoise (config, view, filerule); // pass 1 (detections->allSources)
 
     // define new sources based on only the new peaks
     // NOTE: new sources are saved on detections->newSources
-    psphotSourceStats (config, view, "PSPHOT.INPUT", false); // pass 2 (detections->newSources)
+    psphotSourceStats (config, view, filerule, false); // pass 2 (detections->newSources)
 
     // set source type
     // NOTE: apply only to detections->newSources
-    if (!psphotRoughClass (config, view, "PSPHOT.INPUT")) { // pass 2 (detections->newSources)
+    if (!psphotRoughClass (config, view, filerule)) { // pass 2 (detections->newSources)
         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // create full input models, set the radius to fitRadius, set circular fit mask
     // NOTE: apply only to detections->newSources
-    psphotGuessModels (config, view, "PSPHOT.INPUT"); // pass 2 (detections->newSources)
+    psphotGuessModels (config, view, filerule); // pass 2 (detections->newSources)
 
     // replace all sources so fit below applies to all at once
     // NOTE: apply only to OLD sources (which have been subtracted)
-    psphotReplaceAllSources (config, view, "PSPHOT.INPUT"); // pass 2
+    psphotReplaceAllSources (config, view, filerule); // pass 2
 
     // merge the newly selected sources into the existing list
     // NOTE: merge OLD and NEW
     // XXX check on free of sources...
-    psphotMergeSources (config, view, "PSPHOT.INPUT"); // (detections->newSources + detections->allSources -> detections->allSources)
+    psphotMergeSources (config, view, filerule); // (detections->newSources + detections->allSources -> detections->allSources)
 
     // NOTE: apply to ALL sources
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", true); // pass 3 (detections->allSources)
+    psphotFitSourcesLinear (config, view, filerule, true); // pass 3 (detections->allSources)
 
 pass1finish:
@@ -194,8 +199,8 @@
     // measure source size for the remaining sources
     // NOTE: applies only to NEW (unmeasured) sources
-    psphotSourceSize (config, view, "PSPHOT.INPUT", false); // pass 2 (detections->allSources)
-
-    psphotExtendedSourceAnalysis (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
-    psphotExtendedSourceFits (config, view, "PSPHOT.INPUT"); // pass 1 (detections->allSources)
+    psphotSourceSize (config, view, filerule, false); // pass 2 (detections->allSources)
+
+    psphotExtendedSourceAnalysis (config, view, filerule); // pass 1 (detections->allSources)
+    psphotExtendedSourceFits (config, view, filerule); // pass 1 (detections->allSources)
 
 finish:
@@ -205,15 +210,15 @@
 
     // measure aperture photometry corrections
-    if (!psphotApResid (config, view, "PSPHOT.INPUT")) { // pass 1 (detections->allSources)
+    if (!psphotApResid (config, view, filerule)) { // pass 1 (detections->allSources)
         psLogMsg ("psphot", 3, "failed on psphotApResid");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // calculate source magnitudes
-    if (!psphotMagnitudes(config, view, "PSPHOT.INPUT")) { // pass 1 (detections->allSources)
+    if (!psphotMagnitudes(config, view, filerule)) { // pass 1 (detections->allSources)
       psErrorStackPrint(stderr, "Unable to do magnitudes.");
         psErrorClear();
     }
-    if (!psphotEfficiency(config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotEfficiency(config, view, filerule)) { // pass 1
         psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
         psErrorClear();
@@ -224,20 +229,20 @@
 
     // replace background in residual image
-    if (!psphotSkyReplace (config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotSkyReplace (config, view, filerule)) { // pass 1
       psErrorStackPrint(stderr, "Unable to replace sky");
       psErrorClear();
 
 /*       psLogMsg("psphot", 3, "failed on psphotSkyReplace"); */
-/*       return(psphotReadoutCleanup(config, view, "PSPHOT.INPUT")); */
+/*       return(psphotReadoutCleanup(config, view, filerule)); */
     }
     // drop the references to the image pixels held by each source
-    if (!psphotSourceFreePixels (config, view, "PSPHOT.INPUT")) { // pass 1
+    if (!psphotSourceFreePixels (config, view, filerule)) { // pass 1
       psErrorStackPrint(stderr, "Unable to free source pixels");
       psErrorClear();
 
 /*       psLogMsg ("psphot", 3, "failed on psphotSourceFreePixels"); */
-/*       return(psphotReadoutCleanup(config, view, "PSPHOT.INPUT")); */
+/*       return(psphotReadoutCleanup(config, view, filerule)); */
     }
     // create the exported-metadata and free local data
-    return psphotReadoutCleanup(config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup(config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotReadoutCleanup.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadoutCleanup.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadoutCleanup.c	(revision 30118)
@@ -19,6 +19,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotReadoutFindPSF.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadoutFindPSF.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadoutFindPSF.c	(revision 30118)
@@ -3,10 +3,10 @@
 // in this psphotReadout-variant, we are only trying to determine the PSF given an existing set
 // of input source positions to use as initial PSF stars.
-bool psphotReadoutFindPSF(pmConfig *config, const pmFPAview *view, psArray *inSources) {
+bool psphotReadoutFindPSF(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources) {
 
     psTimerStart ("psphotReadout");
 
-    // set the photcode for the PSPHOT.INPUT
-    if (!psphotAddPhotcode(config, view, "PSPHOT.INPUT")) {
+    // set the photcode for the input
+    if (!psphotAddPhotcode(config, view, filerule)) {
         psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -14,18 +14,18 @@
 
     // Generate the mask and variance images, including the user-defined analysis region of interest
-    psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT");
+    psphotSetMaskAndVariance (config, view, filerule);
 
     // Note that in this implementation, we do NOT model the background and we do not
     // attempt to detect the sources in the image
 
-    // include externally-supplied sources (supplied as PSPHOT.INPUT.CMF)
-    // XXX we assume a single set of input sources is supplied
-    if (!psphotDetectionsFromSources (config, view, "PSPHOT.INPUT", inSources)) {
+    // include the externally-supplied sources (inSources)
+    // (we assume a single set of input sources is supplied)
+    if (!psphotDetectionsFromSources (config, view, filerule, inSources)) {
         psError(PSPHOT_ERR_ARGUMENTS, true, "Can't find PSF stars");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct detections->newSources and measure basic stats (moments, local sky)
-    if (!psphotSourceStats(config, view, "PSPHOT.INPUT", true)) {
+    if (!psphotSourceStats(config, view, filerule, true)) {
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
 	return false;
@@ -33,5 +33,5 @@
 
     // peak flux is wrong : use the peak measured in the moments analysis:
-    if (!psphotRepairLoadedSources(config, view, "PSPHOT.INPUT")) {
+    if (!psphotRepairLoadedSources(config, view, filerule)) {
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to repair sources");
 	return false;
@@ -39,17 +39,17 @@
 
     // classify sources based on moments, brightness (psf is not known)
-    if (!psphotRoughClass (config, view, "PSPHOT.INPUT")) {
+    if (!psphotRoughClass (config, view, filerule)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough source class");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
-    if (!psphotImageQuality (config, view, "PSPHOT.INPUT")) {
+    if (!psphotImageQuality (config, view, filerule)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
-    if (!psphotChoosePSF(config, view, "PSPHOT.INPUT")) {
+    if (!psphotChoosePSF(config, view, filerule)) {
         psError(PSPHOT_ERR_PSF, false, "Failed to construct a psf model");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
@@ -59,23 +59,23 @@
     // fits from that analysis, or run the linear PSF fit for all objects currently in hand
     // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
-    psphotGuessModels (config, view, "PSPHOT.INPUT");
+    psphotGuessModels (config, view, filerule);
 # endif
 
     // merge the newly selected sources into the existing list
     // NOTE: merge OLD and NEW
-    psphotMergeSources (config, view, "PSPHOT.INPUT"); 
+    psphotMergeSources (config, view, filerule); 
 
 # if 0
     // measure aperture photometry corrections
-    if (!psphotApResid (config, view, "PSPHOT.INPUT")) {
+    if (!psphotApResid (config, view, filerule)) {
         psLogMsg ("psphot", 3, "failed on psphotApResid");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 # endif
 
     // drop the references to the image pixels held by each source
-    psphotSourceFreePixels(config, view, "PSPHOT.INPUT");
+    psphotSourceFreePixels(config, view, filerule);
 
     // create the exported-metadata and free local data
-    return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup (config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotReadoutForcedKnownSources.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadoutForcedKnownSources.c	(revision 30118)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadoutForcedKnownSources.c	(revision 30118)
@@ -0,0 +1,56 @@
+# include "psphotInternal.h"
+
+// in this psphotReadout-variant, we are only measuring the photometry for known source
+// position, using a supplied PSF
+bool psphotReadoutForcedKnownSources(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources) {
+
+    psTimerStart ("psphotReadout");
+
+    // remove cruft from the input analysis structure
+    if (!psphotCleanInputs (config, view, filerule)) {
+        psError (PSPHOT_ERR_PROG, false, "trouble setting up the inputs");
+        return false;
+    }
+
+    // set the photcode for this image
+    if (!psphotAddPhotcode(config, view, filerule)) {
+        psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
+        return false;
+    }
+
+    // Generate the mask and weight images, including the user-defined analysis region of interest
+    psphotSetMaskAndVariance (config, view, filerule);
+
+    // Note that in this implementation, we do NOT model the background and we do not
+    // attempt to detect the sources in the image
+
+    if (!psphotAddKnownSources (config, view, filerule, inSources)) {
+	psError(PSPHOT_ERR_UNKNOWN, false, "failure to load supplied sources");
+	return false;
+    }
+
+    if (!psphotLoadPSF (config, view, filerule)) {
+    	// this only happens if we had a programming error in psphotLoadPSF
+        psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
+        return psphotReadoutCleanup (config, view, filerule);
+    }
+
+    // construct an initial model for each object
+    psphotGuessModels (config, view, filerule);
+
+    // merge the newly selected sources into the existing list
+    // NOTE: merge OLD and NEW
+    psphotMergeSources (config, view, filerule); 
+
+    // linear PSF fit to source peaks
+    psphotFitSourcesLinear (config, view, filerule, false);
+
+    // calculate source magnitudes
+    psphotMagnitudes(config, view, filerule);
+
+    // drop the references to the image pixels held by each source
+    psphotSourceFreePixels (config, view, filerule);
+
+    // create the exported-metadata and free local data
+    return psphotReadoutCleanup (config, view, filerule);
+}
Index: /branches/czw_branch/20101203/psphot/src/psphotReadoutKnownSources.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadoutKnownSources.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadoutKnownSources.c	(revision 30118)
@@ -3,10 +3,10 @@
 // in this psphotReadout-variant, we are only measuring the photometry for known sources, using
 // a PSF generated for this observation from those sources
-bool psphotReadoutKnownSources(pmConfig *config, const pmFPAview *view, psArray *inSources) {
+bool psphotReadoutKnownSources(pmConfig *config, const pmFPAview *view, const char *filerule, psArray *inSources) {
 
     psTimerStart ("psphotReadout");
 
     // set the photcode for this image
-    if (!psphotAddPhotcode(config, view, "PSPHOT.INPUT")) {
+    if (!psphotAddPhotcode(config, view, filerule)) {
         psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -14,5 +14,5 @@
 
     // Generate the mask and weight images, including the user-defined analysis region of interest
-    psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT");
+    psphotSetMaskAndVariance (config, view, filerule);
 
     // Note that in this implementation, we do NOT model the background and we do not
@@ -20,11 +20,11 @@
 
     // include externally-supplied sources (supplied as PSPHOT.INPUT.CMF)
-    if (!psphotDetectionsFromSources (config, view, "PSPHOT.INPUT", inSources)) {
+    if (!psphotDetectionsFromSources (config, view, filerule, inSources)) {
         psError(PSPHOT_ERR_ARGUMENTS, true, "Can't find PSF stars");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct sources and measure basic stats
-    if (!psphotSourceStats (config, view, "PSPHOT.INPUT", true)) {
+    if (!psphotSourceStats (config, view, filerule, true)) {
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
 	return false;
@@ -32,5 +32,5 @@
 
     // peak flux is wrong : use the peak measured in the moments analysis:
-    if (!psphotRepairLoadedSources(config, view, "PSPHOT.INPUT")) {
+    if (!psphotRepairLoadedSources(config, view, filerule)) {
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to repair sources");
 	return false;
@@ -38,37 +38,37 @@
 
     // classify sources based on moments, brightness (psf is not known)
-    if (!psphotRoughClass (config, view, "PSPHOT.INPUT")) {
+    if (!psphotRoughClass (config, view, filerule)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failed to determine rough source class");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
-    if (!psphotChoosePSF (config, view, "PSPHOT.INPUT")) {
+    if (!psphotChoosePSF (config, view, filerule)) {
         psError(PSPHOT_ERR_PSF, false, "Failed to construct a psf model");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct an initial model for each object
-    psphotGuessModels (config, view, "PSPHOT.INPUT");
+    psphotGuessModels (config, view, filerule);
 
     // merge the newly selected sources into the existing list
     // NOTE: merge OLD and NEW
-    psphotMergeSources (config, view, "PSPHOT.INPUT"); 
+    psphotMergeSources (config, view, filerule); 
 
     // linear PSF fit to source peaks
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", false);
+    psphotFitSourcesLinear (config, view, filerule, false);
 
     // measure aperture photometry corrections
-    if (!psphotApResid (config, view, "PSPHOT.INPUT")) {
+    if (!psphotApResid (config, view, filerule)) {
         psLogMsg ("psphot", 3, "failed on psphotApResid");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // calculate source magnitudes
-    psphotMagnitudes(config, view, "PSPHOT.INPUT");
+    psphotMagnitudes(config, view, filerule);
 
     // drop the references to the image pixels held by each source
-    psphotSourceFreePixels (config, view, "PSPHOT.INPUT");
+    psphotSourceFreePixels (config, view, filerule);
 
     // create the exported-metadata and free local data
-    return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup (config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotReadoutMinimal.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReadoutMinimal.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReadoutMinimal.c	(revision 30118)
@@ -7,5 +7,5 @@
 // NOTE: ppSub needs to perform extended source analysis for comets and trails.
 
-bool psphotReadoutMinimal(pmConfig *config, const pmFPAview *view) {
+bool psphotReadoutMinimal(pmConfig *config, const pmFPAview *view, const char *filerule) {
 
     // measure the total elapsed time in psphotReadout.  XXX the current threading plan
@@ -18,5 +18,5 @@
 
     // set the photcode for this image
-    if (!psphotAddPhotcode(config, view, "PSPHOT.INPUT")) {
+    if (!psphotAddPhotcode(config, view, filerule)) {
         psError(PSPHOT_ERR_CONFIG, false, "trouble defining the photcode");
         return false;
@@ -24,63 +24,63 @@
 
     // Generate the mask and weight images, including the user-defined analysis region of interest
-    psphotSetMaskAndVariance (config, view, "PSPHOT.INPUT");
+    psphotSetMaskAndVariance (config, view, filerule);
 
     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are saved on readout->analysis
-    if (!psphotLoadPSF (config, view)) {
+    if (!psphotLoadPSF (config, view, filerule)) {
       psError (PSPHOT_ERR_CONFIG, false, "missing psf model");
-      return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+      return psphotReadoutCleanup (config, view, filerule);
     }
 
     // find the detections (by peak and/or footprint) in the image. (final pass)
-    if (!psphotFindDetections(config, view, "PSPHOT.INPUT", false)) {
+    if (!psphotFindDetections(config, view, filerule, false)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct sources and measure basic stats (saved on detections->newSources)
-    if (!psphotSourceStats (config, view, "PSPHOT.INPUT", false)) { // pass 1
+    if (!psphotSourceStats (config, view, filerule, false)) { // pass 1
         psError(PSPHOT_ERR_UNKNOWN, false, "failure to generate sources");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // find blended neighbors of very saturated stars
-    psphotDeblendSatstars (config, view, "PSPHOT.INPUT");
+    psphotDeblendSatstars (config, view, filerule);
 
     // mark blended peaks PS_SOURCE_BLEND
-    if (!psphotBasicDeblend (config, view, "PSPHOT.INPUT")) {
+    if (!psphotBasicDeblend (config, view, filerule)) {
         psLogMsg ("psphot", 3, "failed on deblend analysis");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // classify sources based on moments, brightness (use supplied psf shape parameters)
-    if (!psphotRoughClass (config, view, "PSPHOT.INPUT")) {
+    if (!psphotRoughClass (config, view, filerule)) {
         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
-        return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+        return psphotReadoutCleanup (config, view, filerule);
     }
 
     // construct an initial model for each object
-    psphotGuessModels (config, view, "PSPHOT.INPUT");
+    psphotGuessModels (config, view, filerule);
 
     // merge the newly selected sources into the existing list
-    psphotMergeSources (config, view, "PSPHOT.INPUT");
+    psphotMergeSources (config, view, filerule);
 
     // linear PSF fit to source peaks
-    psphotFitSourcesLinear (config, view, "PSPHOT.INPUT", false);
+    psphotFitSourcesLinear (config, view, filerule, false);
 
 // XXX eventually, add the extended source fits here
 # if (0)
     // measure source size for the remaining sources
-    psphotSourceSize (config, view, "PSPHOT.INPUT");
+    psphotSourceSize (config, view, filerule);
 
-    psphotExtendedSourceAnalysis (config, view, "PSPHOT.INPUT");
+    psphotExtendedSourceAnalysis (config, view, filerule);
 
-    psphotExtendedSourceFits (config, view, "PSPHOT.INPUT");
+    psphotExtendedSourceFits (config, view, filerule);
 # endif
 
     // calculate source magnitudes
-    psphotMagnitudes(config, view, "PSPHOT.INPUT");
+    psphotMagnitudes(config, view, filerule);
 
     // XXX ensure this is measured if the analysis succeeds (even if quality is low)
-    if (!psphotEfficiency(config, view, "PSPHOT.INPUT")) {
+    if (!psphotEfficiency(config, view, filerule)) {
         psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
         psErrorClear();
@@ -88,7 +88,7 @@
 
     // drop the references to the image pixels held by each source
-    psphotSourceFreePixels (config, view, "PSPHOT.INPUT");
+    psphotSourceFreePixels (config, view, filerule);
 
     // create the exported-metadata and free local data
-    return psphotReadoutCleanup (config, view, "PSPHOT.INPUT");
+    return psphotReadoutCleanup (config, view, filerule);
 }
Index: /branches/czw_branch/20101203/psphot/src/psphotReplaceUnfit.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotReplaceUnfit.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotReplaceUnfit.c	(revision 30118)
@@ -31,11 +31,10 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
 	if (!psphotReplaceAllSourcesReadout (config, view, filerule, i, recipe)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to replace all sources for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed to replace all sources for %s entry %d", filerule, i);
 	    return false;
 	}
Index: /branches/czw_branch/20101203/psphot/src/psphotRoughClass.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotRoughClass.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotRoughClass.c	(revision 30118)
@@ -16,6 +16,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
Index: /branches/czw_branch/20101203/psphot/src/psphotSkyReplace.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSkyReplace.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSkyReplace.c	(revision 30118)
@@ -5,6 +5,5 @@
     bool status = true;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
Index: /branches/czw_branch/20101203/psphot/src/psphotSourceFreePixels.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSourceFreePixels.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSourceFreePixels.c	(revision 30118)
@@ -3,8 +3,5 @@
 bool psphotSourceFreePixels (pmConfig *config, const pmFPAview *view, const char *filerule)
 {
-    bool status = true;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotSourceMatch.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSourceMatch.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSourceMatch.c	(revision 30118)
@@ -6,15 +6,12 @@
 psArray *psphotMatchSources (pmConfig *config, const pmFPAview *view, const char *filerule) 
 {
-    bool status = true;
-
     psArray *objects = psArrayAllocEmpty(100);
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
         if (!psphotMatchSourcesReadout (objects, config, view, filerule, i)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to merge sources for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed to merge sources for %s entry %d", filerule, i);
 	    psFree (objects);
             return NULL;
@@ -162,6 +159,5 @@
     psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
 
-    int nImages = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int nImages = psphotFileruleCount(config, filerule);
 
     // generate look-up arrays for detections and readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotSourceSize.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSourceSize.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSourceSize.c	(revision 30118)
@@ -49,6 +49,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
@@ -60,5 +59,5 @@
         if (i == chisqNum) continue; // skip chisq image
         if (!psphotSourceSizeReadout (config, view, filerule, i, recipe, getPSFsize)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed on source size analysis for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed on source size analysis for %s entry %d", filerule, i);
             return false;
         }
Index: /branches/czw_branch/20101203/psphot/src/psphotSourceStats.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSourceStats.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSourceStats.c	(revision 30118)
@@ -14,6 +14,5 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // skip the chisq image (optionally?)
Index: /branches/czw_branch/20101203/psphot/src/psphotStackChisqImage.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotStackChisqImage.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotStackChisqImage.c	(revision 30118)
@@ -8,6 +8,4 @@
 bool psphotStackChisqImage (pmConfig *config, const pmFPAview *view, const char *ruleDet, const char *ruleCnv)
 {
-    bool status = false;
-
     psTimerStart ("psphot.chisq.image");
 
@@ -17,6 +15,5 @@
     pmReadout *chiReadout = NULL;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     // loop over the available readouts
@@ -28,7 +25,4 @@
         }
     }
-
-    num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
 
     psMetadataAddS32(config->arguments, PS_LIST_TAIL, "PSPHOT.CHISQ.NUM", PS_META_REPLACE, "", num);
@@ -125,6 +119,5 @@
     psAssert (status, "programming error: must define PSPHOT.CHISQ.NUM");
 
-    int inputNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int inputNum = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     pmFPAfileRemoveSingle (config->files, filerule, chisqNum);
Index: /branches/czw_branch/20101203/psphot/src/psphotStackImageLoop.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotStackImageLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotStackImageLoop.c	(revision 30118)
@@ -105,11 +105,8 @@
 bool GetAstrometryFPA (pmConfig *config, pmFPAview *view) {
 
-    bool status = false;
-
     bool foundAstrometry = false;
     bool bilevelAstrometry = false;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     // loop over the available readouts
@@ -158,8 +155,5 @@
 bool GetAstrometryChip (pmConfig *config, pmFPAview *view, bool bilevelAstrometry) {
 
-    bool status = false;
-
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     // loop over the available readouts
@@ -220,10 +214,7 @@
 bool SetAstrometryFPA (pmConfig *config, pmFPAview *view, bool bilevelAstrometry) {
 
-    bool status = false;
-
     if (!bilevelAstrometry) return true;
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     // loop over the available readouts
Index: /branches/czw_branch/20101203/psphot/src/psphotStackMatchPSFs.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotStackMatchPSFs.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotStackMatchPSFs.c	(revision 30118)
@@ -8,6 +8,5 @@
     psAssert(recipe, "We've thrown an error on this before.");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, "PSPHOT.INPUT");
 
     // 'options' carries info needed to perform the stack matching
Index: /branches/czw_branch/20101203/psphot/src/psphotStackReadout.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotStackReadout.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotStackReadout.c	(revision 30118)
@@ -52,5 +52,5 @@
     // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are determined and saved on
     // readout->analysis XXX this function currently only works with a single PSPHOT.INPUT
-    if (!psphotLoadPSF (config, view)) {
+    if (!psphotLoadPSF (config, view, STACK_RAW)) {
         psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
         return psphotReadoutCleanup (config, view, STACK_OUT);
Index: /branches/czw_branch/20101203/psphot/src/psphotSubtractBackground.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotSubtractBackground.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotSubtractBackground.c	(revision 30118)
@@ -132,11 +132,10 @@
     psAssert (recipe, "missing recipe?");
 
-    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+    int num = psphotFileruleCount(config, filerule);
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
 	if (!psphotSubtractBackgroundReadout (config, view, filerule, i, recipe)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to subtract background for PSPHOT.INPUT entry %d", i);
+	    psError (PSPHOT_ERR_CONFIG, false, "failed to subtract background for %s entry %d", filerule, i);
 	    return false;
 	}
Index: /branches/czw_branch/20101203/psphot/src/psphotTest.c
===================================================================
--- /branches/czw_branch/20101203/psphot/src/psphotTest.c	(revision 30117)
+++ /branches/czw_branch/20101203/psphot/src/psphotTest.c	(revision 30118)
@@ -137,5 +137,5 @@
     psMetadataItem *mdi;
 
-    psMetadataConfigWrite (header, argv[2]);
+    psMetadataConfigWrite (header, argv[2], NULL);
 
     // attempt to write image with NAXIS = 0
Index: /branches/czw_branch/20101203/pstamp/scripts/pstamp_job_run.pl
===================================================================
--- /branches/czw_branch/20101203/pstamp/scripts/pstamp_job_run.pl	(revision 30117)
+++ /branches/czw_branch/20101203/pstamp/scripts/pstamp_job_run.pl	(revision 30118)
@@ -277,9 +277,13 @@
         # silently skip them if they don't exist. Perhaps this should be
         # detected in pstampparse so that the user can be notified with 
-        # a message in parse_error.txt ("warp do not have a background model")
-        my $cmf_file = $params->{cmf} if ($options & $PSTAMP_SELECT_CMF);
+        # a message in parse_error.txt ("warp does not have a background model")
         my $psf_file = $params->{psf} if ($options & $PSTAMP_SELECT_PSF);
         my $backmdl_file = $params->{backmdl} if ($options & $PSTAMP_SELECT_BACKMDL);
         my $pattern_file = $params->{pattern} if ($options & $PSTAMP_SELECT_BACKMDL);
+        my $cmf_file;
+        if ($stage ne 'chip') {
+            # we don't ship chip stage cmf files because they may not be censored
+            $cmf_file = $params->{cmf} if ($options & $PSTAMP_SELECT_CMF);
+        }
 
         my $outdir = dirname($output_base);
Index: /branches/czw_branch/20101203/pstamp/scripts/pstampparse.pl
===================================================================
--- /branches/czw_branch/20101203/pstamp/scripts/pstampparse.pl	(revision 30117)
+++ /branches/czw_branch/20101203/pstamp/scripts/pstampparse.pl	(revision 30118)
@@ -126,4 +126,26 @@
 }
 
+# Adjust the label for requests coming in over the web interaface
+
+my $label_changed = 0;
+if ($label and $label eq "WEB.UP") {
+    my $lcname = lc($req_name);
+    if ($lcname =~ /pitt/) {
+        $label = "PITT";
+        $label_changed = 1;
+    } elsif ($lcname =~ /cfa/) {
+        $label = "CFA";
+        $label_changed = 1;
+    } elsif ($lcname =~ /durham/) {
+        $label = "DURHAM";
+        $label_changed = 1;
+    } elsif ($lcname =~ /qub/) {
+        $label = "QUB";
+        $label_changed = 1;
+    }
+    print "Setting label for $req_name to $label\n" if $label_changed;
+}
+
+
 if ($req_id and !$no_update) {
     # update the database with the request name. This will be used as the
@@ -131,4 +153,5 @@
     my $command = "$pstamptool -updatereq -req_id $req_id  -set_name $req_name";
     $command .= " -set_outProduct $product";
+    $command .= " -set_label $label" if $label_changed;
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
         run(command => $command, verbose => $verbose);
Index: /branches/czw_branch/20101203/pstamp/src/ppstampMakeStamp.c
===================================================================
--- /branches/czw_branch/20101203/pstamp/src/ppstampMakeStamp.c	(revision 30117)
+++ /branches/czw_branch/20101203/pstamp/src/ppstampMakeStamp.c	(revision 30118)
@@ -320,5 +320,6 @@
         }
         if (readout->mask) {
-            outReadout->mask = extractStamp(readout->mask, extractRegion,  0);
+            psImageMaskType maskInitValue = pmConfigMaskGet("BLANK", config);
+            outReadout->mask = extractStamp(readout->mask, extractRegion,  maskInitValue);
             if (!outReadout->mask) {
                 psError(PS_ERR_UNKNOWN, false, "failed to create postage stamp mask image\n");
Index: /branches/czw_branch/20101203/pswarp/src/pswarpLoop.c
===================================================================
--- /branches/czw_branch/20101203/pswarp/src/pswarpLoop.c	(revision 30117)
+++ /branches/czw_branch/20101203/pswarp/src/pswarpLoop.c	(revision 30118)
@@ -384,5 +384,5 @@
 
         // measure the PSF using these sources
-        if (!psphotReadoutFindPSF(config, view, sources)) {
+        if (!psphotReadoutFindPSF(config, view, "PSPHOT.INPUT", sources)) {
             // This is likely a data quality issue
             // XXX Split into multiple cases using error codes?
Index: /branches/czw_branch/20101203/tools/czarplot.pl
===================================================================
--- /branches/czw_branch/20101203/tools/czarplot.pl	(revision 30117)
+++ /branches/czw_branch/20101203/tools/czarplot.pl	(revision 30118)
@@ -126,11 +126,20 @@
 
 
-my $plotter = new czartool::Plotter(
-        $gpc1Db, 
-        $czarDb, 
-        "%Y%m%d-%H%M%S", 
-        $savingToFile ? "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8" : "X11", 
-        $path, 
-        $save_temps);
+my $plotter = undef; 
+if ($savingToFile) {
+
+    $plotter = czartool::Plotter->new_file(
+            $gpc1Db,
+            $czarDb,
+            $path,
+            $save_temps);
+}
+else {
+
+    $plotter = czartool::Plotter->new_display(
+            $gpc1Db, 
+            $czarDb, 
+            $save_temps);
+}
 
 # sort out times
@@ -168,5 +177,5 @@
 elsif ($nebulous) {$plotter->plotDiskUsageHistogram();}
 if ($magicMask) {
-    
+
     if ($exposureId) {$plotter->plotMagicMaskFractionForThisExposure($exposureId);}
     else {$plotter->plotMagicMaskFraction($begin, $end);}
Index: /branches/czw_branch/20101203/tools/czarpoll.pl
===================================================================
--- /branches/czw_branch/20101203/tools/czarpoll.pl	(revision 30117)
+++ /branches/czw_branch/20101203/tools/czarpoll.pl	(revision 30118)
@@ -14,5 +14,5 @@
 use czartool::Burntool;
 use czartool::DayMetrics;
-
+use czartool::MetricsIndex;
 
 my $period = 60;
@@ -29,5 +29,5 @@
 my $nebulous = new czartool::Nebulous($czarDb);
 my $pantasks = new czartool::Pantasks();
-my $plotter = new czartool::Plotter($gpc1Db, $czarDb, "%Y%m%d-%H%M%S", "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8", "/tmp", $save_temps); # TODO hardcoded font path
+my $plotter = czartool::Plotter->new_file($gpc1Db, $czarDb, "/tmp", $save_temps); 
 my $burntool = new czartool::Burntool();
 
@@ -108,40 +108,51 @@
     my $newState = undef;
     my $nsStatus = undef;
-    my $lastDay = strftime('%Y-%m-%d', localtime);
     my $today = undef;
-    my $doneMetricsToday = 1;
-
+    my $yesterday = undef;
+    my $newDayTime = "18:00";
+    my $lastDayDailyTasks = "2010-01-01";
+
+    # main polling loop
     while (1) {
 
-        # check whether day has changed. if so, cleanup tables from previous day and optimize
+        # sort out times
         $today = strftime('%Y-%m-%d', localtime);
-        if ($czarDb->isBefore($lastDay, $today)) {
-        
+        $yesterday = $czarDb->subtractInterval($today, "1 DAY");
+        $end = $czarDb->getNowTimestamp();
+
+        # if before 18:00 today, then start plots from 18:00 yesterday
+        if ($czarDb->isBefore($end, "$today $newDayTime")) {$begin = "$yesterday $newDayTime";}
+        # if after 18:00 today, then perform some daily tasks and start plots from 18:00 today
+        else {
+            
+            $begin = "$today $newDayTime";
+
+            # check whether yesterday was cleaned. if not, cleanup tables and optimize
+            if ($lastDayDailyTasks ne $yesterday) {
+   
+                print "* performing daily tasks (clean-up, metrics)";
+
+                # create metrics for last 24 hours
+                print "* Creating metrics for last 24 hours\n";
+                # TODO hardcoded path needs to be in config
+                my $dayMetrics = new czartool::DayMetrics($gpc1Db, 
+                        $czarDb, 
+                        "/data/ipp004.0/ipp/ippMetrics/", 
+                        1, 0, $today); 
+                $dayMetrics->writeHTML();
+
+                # now update metrics index page
+                my $metricsIndex = new czartool::MetricsIndex($gpc1Db, 
+                        $czarDb, 
+                        "/data/ipp004.0/ipp/ippMetrics/", 
+                        1, 0); 
+                $metricsIndex->writeHTML();
+
+                # now cleanup tables from yesterday and optimize
                 print "* New day - performing cleanup\n";
-                $czarDb->cleanupDateRange($lastDay, $lastDay, "30 MINUTE");
+                $czarDb->cleanupDateRange($yesterday, $yesterday, "30 MINUTE");
                 $czarDb->optimize();
-                $lastDay = $today;
-                $doneMetricsToday = 0;
-        }
-
-        # sort out times
-        $begin = strftime('%Y-%m-%d 06:35', localtime);
-        $end = $czarDb->getNowTimestamp();
-
-        # if time now is after 06:35am, then create metrics for past 24 hours
-        if (!$doneMetricsToday && $czarDb->isBefore($begin, $end)) {
-        
-                print "* Creating metrics for last 24 hours\n";
-                my $yesterday = $czarDb->subtractInterval($today, "1 DAY");
-                # TODO hardcoded path needs to be in config
-                my $dayMetrics = new czartool::DayMetrics($gpc1Db, $czarDb, "/data/ipp004.0/ipp/ippMetrics/", 1, 0, $yesterday); 
-                $dayMetrics->writeHTML();
-                $doneMetricsToday = 1;
-        }
-
-        # if time now is before 06:35am, include data from previous day
-        if ($czarDb->isBefore($end, $begin)) {
-
-            $begin = $czarDb->subtractInterval($begin, "1 DAY");
+                $lastDayDailyTasks = $yesterday;
+            }
         }
 
@@ -237,5 +248,5 @@
 
         $plotter->createLogAndLinearTimeSeries($allServerLabels,  $stage, $begin, $end); # TODO must be a neater way...
-        $plotter->createRateTimeSeries($allServerLabels, $stage, $begin, $end, undef, 0);
+            $plotter->createRateTimeSeries($allServerLabels, $stage, $begin, $end, undef, 0);
     }
 }
@@ -261,5 +272,5 @@
     my $server = undef;
     my $state = undef;
-    
+
     foreach $stage (@stages) {
 
Index: /branches/czw_branch/20101203/tools/czartool/DayMetrics.pm
===================================================================
--- /branches/czw_branch/20101203/tools/czartool/DayMetrics.pm	(revision 30117)
+++ /branches/czw_branch/20101203/tools/czartool/DayMetrics.pm	(revision 30118)
@@ -37,6 +37,8 @@
     $self->{day} = $_[6];
 
+    my $yesterday =  $self->{czarDb}->subtractInterval($self->{day}, "1 DAY");
+
     # sort out times
-    $self->{begin} =  "$self->{day} 06:00";
+    $self->{begin} =  "$yesterday 18:00";
     $self->{end} = $self->{czarDb}->addInterval($self->{begin}, "1 DAY");
     $self->{burntoolEnd} = $self->{czarDb}->addInterval($self->{begin}, "12 HOUR");
Index: /branches/czw_branch/20101203/tools/czartool/Metrics.pm
===================================================================
--- /branches/czw_branch/20101203/tools/czartool/Metrics.pm	(revision 30117)
+++ /branches/czw_branch/20101203/tools/czartool/Metrics.pm	(revision 30118)
@@ -35,9 +35,7 @@
 
     # instantiate a plotter object
-    $self->{plotter} = new czartool::Plotter(
+    $self->{plotter} = czartool::Plotter->new_file(
             $self->{gpc1Db},
             $self->{czarDb},
-            "%Y%m%d-%H%M%S",
-            "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8",
             ".",
             $self->{save_temps});
Index: /branches/czw_branch/20101203/tools/czartool/Plotter.pm
===================================================================
--- /branches/czw_branch/20101203/tools/czartool/Plotter.pm	(revision 30117)
+++ /branches/czw_branch/20101203/tools/czartool/Plotter.pm	(revision 30118)
@@ -10,8 +10,7 @@
 my @allStages = ("burntool", "chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
 
-
-###########################################################################
-#
-# Constructor
+###########################################################################
+#
+# Main constructor with all arguments
 #
 ###########################################################################
@@ -30,4 +29,48 @@
     return $self;
 }
+
+###########################################################################
+#
+# Constructor sending all plots to file
+#
+###########################################################################
+sub new_file {
+    my $class = shift;
+    my $self = {
+        _gpc1Db => shift,
+        _czarDb => shift,
+        _outputPath => shift,
+        _save_temps => shift,
+                                                    };
+
+    $self->{_dateFormat} = "%Y%m%d-%H%M%S";
+    $self->{_outputFormat} = "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8"; # TODO path needs to be in config
+
+        bless $self, $class;
+    return $self;
+}
+
+###########################################################################
+#
+# Constructor sending all plots to an X window
+#
+###########################################################################
+sub new_display {
+    my $class = shift;
+    my $self = {
+        _gpc1Db => shift,
+        _czarDb => shift,
+        _save_temps => shift,
+    };
+
+    $self->{_dateFormat} = "%Y%m%d-%H%M%S";
+    $self->{_outputFormat} = "X11";
+    $self->{_outputPath} = undef;
+
+    bless $self, $class;
+    return $self;
+}
+
+
 
 ###########################################################################
Index: /branches/czw_branch/20101203/tools/makedistdest
===================================================================
--- /branches/czw_branch/20101203/tools/makedistdest	(revision 30117)
+++ /branches/czw_branch/20101203/tools/makedistdest	(revision 30118)
@@ -13,13 +13,16 @@
 
 my $prod_name;
+my $dbhost;
 
 GetOptions(
            'prod_name=s'     => \$prod_name,
+           'dbhost=s'        => \$dbhost,
 ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --prod_name",
+pod2usage( -msg => "Required options: --prod_name --dbhost",
            -exitval => 3)
-    unless defined $prod_name;  
+    unless defined $prod_name
+    and defined $dbhost;  
 
 my $cmd = "dsprodtool --add $prod_name --type ipp-dist --description $prod_name";
@@ -31,5 +34,5 @@
 die "dsprodtool failed: $rc" if $rc;
 
-$cmd = "disttool -dbname gpc1 -definedestination -ds_dbname ippRequestServer -ds_dbhost ippdb02 -name $prod_name";
+$cmd = "disttool -dbname gpc1 -definedestination -ds_dbname ippRequestServer -ds_dbhost $dbhost -name $prod_name";
 
 $rc = system $cmd;
