Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/ImageSubset.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/ImageSubset.c	(revision 33227)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/ImageSubset.c	(revision 33227)
@@ -0,0 +1,209 @@
+# include "uniphot.h"
+
+typedef struct {
+  float Mcal;
+  float dMcal;
+  unsigned int imageID;
+  unsigned int photom_map_id;
+  unsigned int flags;
+} ImageSubset;
+
+ImageSubset *ImageSubsetLoad(char *filename, int *nimage) {
+
+  int i, Ncol;
+  off_t Nrow;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  *nimage = 0;
+  ImageSubset *image = NULL;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+  
+  // XXX close the fits file here
+
+  // a bit annoying : we read the entire block of data (180M), then extract the columns, then set the image structure values.
+  // this means I need 3 copies in memory at some point.  ugh.
+
+  // need to create and assign to flat-field correction
+  float *Mcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL", type, &Nrow, &Ncol);
+  myAssert (!strcmp(type, "float"), "wrong column type");
+
+  float *dMcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL_ERR", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "float"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *imageID = gfits_get_bintable_column_data (&theader, &ftable, "IMAGE_ID", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *map = gfits_get_bintable_column_data (&theader, &ftable, "PHOTOM_MAP", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *flags = gfits_get_bintable_column_data (&theader, &ftable, "FLAGS", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  // XXX free the fits table data here 
+
+  ALLOCATE (image, ImageSubset, Ncol);
+  for (i = 0; i < Nrow; i++) {
+    image[i].imageID       = imageID[i];
+    image[i].photom_map_id = map[i];
+    image[i].flags         = flags[i];
+    image[i].Mcal          = Mcal[i];
+    image[i].dMcal         = dMcal[i];
+  }
+  fprintf (stderr, "loaded data for %d images\n", Ncol);
+
+  free (Mcal);
+  free (dMcal);
+  free (imageID);
+  free (map);
+  free (flags);
+
+  *nimage = Ncol;
+  return image;
+}
+
+int ImageSubsetSave(char *filename, Image *image, int Nimage) {
+
+  int i, Ncol;
+  off_t Nrow;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  gfits_init_header (&header);
+  header.extend = TRUE;
+  gfits_create_header (&header);
+  gfits_create_matrix (&header, &matrix);
+
+  gfits_create_table_header (&theader, "BINTABLE", FITS);
+
+  gfits_define_bintable_column (&theader, "E", "MCAL", "zero point offset", "magnitudes", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "E", "MCAL_ERR", "zero point error", "magnitudes", 1.0, 0.0);
+
+  // an unsigned int needs to have bzero of 0x8000
+  gfits_define_bintable_column (&theader, "J", "IMAGE_ID", "image ID", NULL, 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "PHOTOM_MAP", "map", NULL, 1.0, 1.0*0x8000);
+  gfits_define_bintable_column (&theader, "J", "FLAGS", "flags", NULL, 1.0, 1.0*0x8000);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  // add the vectors to the output array
+  ALLOCATE (Mcal, float, Nimage);
+  ALLOCATE (dMcal, float, Nimage);
+  ALLOCATE (imageID, unsigned int, Nimage);
+  ALLOCATE (imageID, unsigned int, Nimage);
+
+  for 
+  gfits_set_bintable_column_reformat (&theader, &ftable, vec[j][0].name, "double", vec[j][0].elements.Flt, vec[j][0].Nelements);
+    } else {
+      gfits_set_bintable_column_reformat (&theader, &ftable, vec[j][0].name, "int", vec[j][0].elements.Int, vec[j][0].Nelements);
+      }
+  }
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file for output %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) return (NULL);
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) return (NULL);
+  
+  // XXX close the fits file here
+
+  // a bit annoying : we read the entire block of data (180M), then extract the columns, then set the image structure values.
+  // this means I need 3 copies in memory at some point.  ugh.
+
+  // need to create and assign to flat-field correction
+  float *Mcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL", type, &Nrow, &Ncol);
+  myAssert (!strcmp(type, "float"), "wrong column type");
+
+  float *dMcal = gfits_get_bintable_column_data (&theader, &ftable, "MCAL_ERR", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "float"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *imageID = gfits_get_bintable_column_data (&theader, &ftable, "IMAGE_ID", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *map = gfits_get_bintable_column_data (&theader, &ftable, "PHOTOM_MAP", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  unsigned int *flags = gfits_get_bintable_column_data (&theader, &ftable, "FLAGS", type, &Nrow, &Ncol2);
+  assert (!strcmp(type, "int"), "wrong column type");
+  assert (Ncol == Ncol2, "table length mismatch");
+
+  // XXX free the fits table data here 
+
+  ALLOCATE (image, ImageSubset, Ncol);
+  for (i = 0; i < Nrow; i++) {
+    image[i].imageID       = imageID[i];
+    image[i].photom_map_id = map[i];
+    image[i].flags         = flags[i];
+    image[i].Mcal          = Mcal[i];
+    image[i].dMcal         = dMcal[i];
+  }
+  fprintf (stderr, "loaded data for %d images\n", Ncol);
+
+  free (Mcal);
+  free (dMcal);
+  free (imageID);
+  free (map);
+  free (flags);
+
+  *nimage = Ncol;
+  return image;
+}
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c	(revision 33227)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/setphot_client.c	(revision 33227)
@@ -0,0 +1,56 @@
+# include "uniphot.h"
+
+// setphot_client is run on a remote host and is responsible for updating the catalogs
+// owned by that host.  
+
+// setphot_client -hostname (hostname) -catdir (catdir) -hostdir (hostdir) -images (images)
+// load the SkyTable and HostTable from (catdir) [contains the host responsibilities]
+// load the image data from (images) [contains the zp infomation to apply]
+// loop over tables from SkyTable with my host ID
+// the calling program tells the client which host they are (or host ID?); we do not actually have to run this on the real host
+
+int main (int argc, char **argv) {
+
+  off_t Nimage;
+  ImageSubset *image;
+
+  /* get configuration info, args, lockfile */
+  initialize_setphot_client (argc, argv);
+
+  // need to pass in the CATDIR
+  ImageSubset *image = ImageSubsetLoad (imageFile, &Nimage);
+
+  // just do this normally
+  FlatCorrectionTable *flatcorrTable = FlatCorrectionLoad (flatcorrFile);
+
+  update_setphot(image, Nimage, flatcorrTable);
+
+  exit (0);
+}
+  
+
+/* setphot : set the zero points for images in the db (perhaps based on external information)
+   setphot (zpt_table)
+
+   setphot has 2 modes : basic & ubercal
+
+   * outline of basic mode:
+
+   ** load text table of zpts, time (photcode?)
+   ** load images
+   ** match images to zpts
+   ** set zpts
+   ** load catalogs
+   ** update detection (& averages?)
+
+   * outline of ubercal mode:
+
+   ** load fits table of zpts & time + table of flat-field corrections
+   ** load images
+   ** match images to zpts
+   ** set zpts
+   ** load catalogs
+   ** update detection (& averages?)
+
+ */
+
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/uniphot.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/uniphot.c	(revision 33226)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/uniphot.c	(revision 33227)
@@ -74,5 +74,5 @@
   if (!UPDATE) exit (0);
 
-  update (&db, sgroup, Nsgroup);
+  update_dvo_uniphot (&db, sgroup, Nsgroup);
   dvo_image_unlock (&db); 
 
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update.c	(revision 33226)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update.c	(revision 33227)
@@ -2,5 +2,6 @@
 # include <glob.h>
 
-void update (FITS_DB *db, Group *sgroup, int Nsgroup) {
+// update images & catalogs for uniphot
+void update_dvo_uniphot (FITS_DB *db, Group *sgroup, int Nsgroup) {
 
   off_t i, Nimage, Nkeep, *keep;
@@ -102,5 +103,5 @@
 
     fprintf (stderr, "catalog: %s sgroup: %d %s %f\n", catalog.filename, Nmin, sgroup[Nmin].label, Rmin);
-    update_dvo_catalog (&catalog, &sgroup[Nmin], (Rmin > 2*RADIUS)); 
+    update_catalog_uniphot (&catalog, &sgroup[Nmin], (Rmin > 2*RADIUS)); 
     dvo_catalog_save (&catalog, VERBOSE);
     dvo_catalog_unlock (&catalog);
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_catalog.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_catalog.c	(revision 33226)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_catalog.c	(revision 33227)
@@ -1,5 +1,6 @@
 # include "uniphot.h"
 
-void update_dvo_catalog (Catalog *catalog, Group *sgroup, int warn) {
+// update a single catalog for uniphot
+void update_catalog_uniphot (Catalog *catalog, Group *sgroup, int warn) {
 
   int i, j, m, found;
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot.c	(revision 33226)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot.c	(revision 33227)
@@ -10,5 +10,29 @@
 int update_setphot_parallel () {
 
-   return (TRUE);
+  strcpy (connect, "ssh");
+
+  // load the list of hosts
+  HostTable *table = HostTableLoad (catdir, "HostTable.dat");
+
+  for (i = 0; i < table->Nhosts; i++) {
+
+    char command[1024];
+    snprintf (command, 1024, "setphot_update_catalogs");
+
+    // launch the job on the remote machine (no handshake)
+    int pid = rconnect (connect, table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
+    if (!pid) {
+      if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
+      exit (1);
+    }
+    table->hosts[i].pid; // save for future reference
+
+    // check that all hosts started OK?
+  }
+
+  // watch for stdout / stderr from those jobs...
+  // wait for all of them to complete...
+
+  return (TRUE);
 }      
 
Index: /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot_client.c
===================================================================
--- /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot_client.c	(revision 33227)
+++ /branches/eam_branches/ipp-20111122/Ohana/src/uniphot/src/update_setphot_client.c	(revision 33227)
@@ -0,0 +1,123 @@
+# include "uniphot.h"
+# include <glob.h>
+
+// we want to load a subset of image data for this operation.  we only need:
+// imageID, photom_map_id, Mcal, dMcal, flags.  
+int update_setphot (Image *image, off_t Nimage, FlatCorrectionTable *flatcorr) {
+
+  SkyRegion UserPatch;
+  SkyTable *sky = NULL;
+  SkyList *skylist = NULL;
+  Catalog catalog;
+  off_t i, maxID, *index;
+
+  // create an index for the image IDs
+  maxID = 0;
+  for (i = 0; i < Nimage; i++) {
+    maxID = MAX(maxID, image[i].imageID);
+  }
+  ALLOCATE (index, off_t, maxID + 1);
+  for (i = 0; i < Nimage; i++) {
+    if (!image[i].imageID) continue; // images with ID == 0 are virtual
+    index[image[i].imageID] = i;
+  }
+
+  // load the current sky table (layout of all SkyRegions) 
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  // load the host table
+  hosts = HostTableLoad ();
+  int hostID = XX;
+  HostInfo *host = XX;
+
+  // determine the populated SkyRegions overlapping the requested area (default depth)
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax = 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  // update measurements for each populated catalog
+  for (i = 0; i < skylist[0].Nregions; i++) {
+
+    if (hostID != skylist->regions[i]->hostID) continue;
+    if (!(skylist->regions[i]->hostFlags & DATA_ON_TGT)) continue;
+
+    snprintf (localFilename, 1024, "%s/%s.cpt", host->pathname, skylist->regions[i].name);
+
+    // set up the basic catalog info
+    catalog.filename  = localFilename;
+    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 | LOAD_MISS | LOAD_SECF;
+    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+
+    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
+      fprintf (stderr, "ERROR: failure reading catalog %s\n", catalog.filename);
+      exit (1);
+    }
+    if (!catalog.Naves_disk) {
+      if (VERBOSE) fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    update_catalog_setphot_client (&catalog, image, index, Nimage, flatcorr);
+
+    if (!UPDATE) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+    
+    if (VERBOSE) fprintf (stderr, "saving catalog %s\n", catalog.filename);
+    
+    dvo_catalog_save (&catalog, VERBOSE); 
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+  return (TRUE);
+}      
+
+void update_catalog_setphot_client (Catalog *catalog, Image *image, off_t *index, off_t Nimage, FlatCorrectionTable *flatcorr) {
+
+  off_t i, j, found;
+
+  found = 0;    
+  for (i = 0; i < catalog[0].Naverage; i++) {
+
+    off_t m = catalog[0].average[i].measureOffset;
+    for (j = 0; j < catalog[0].average[i].Nmeasure; j++, m++) {
+      off_t idx = catalog[0].measure[m].imageID;
+      if (idx <= 0) continue; // detections with imageID == 0 do not have a valid image (eg, ref photcode)
+
+      off_t id = index[idx];
+      float Mcal = image[id].Mcal;
+      float dMcal = image[id].dMcal;
+      float Mcal_offset = 0.0;
+
+      // if we know about a flat-field correction, then we need to apply the sub-chip correction
+      int flat_id = image[id].photom_map_id;
+      if (flat_id > 0) {
+	  Mcal_offset = FlatCorrectionOffset (flatcorr, flat_id, catalog[0].measure[m].Xccd, catalog[0].measure[m].Yccd);
+      }
+
+      catalog[0].measure[m].Mcal = Mcal - Mcal_offset;
+      catalog[0].measure[m].dMcal = dMcal;
+
+      // if we are setting the zero points from an UBERCAL database, and this detection is from one of those images,
+      // then tag the measurement as well
+      if (UBERCAL && (image[id].flags & ID_IMAGE_PHOTOM_UBERCAL)) {
+	catalog[0].measure[m].dbFlags |=  ID_MEAS_PHOTOM_UBERCAL;
+      }
+
+      found ++;
+    }
+  }
+
+  if (found) {
+    fprintf (stderr, "found "OFF_T_FMT" matches\n", found);
+  }
+}
