Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrection.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrection.c	(revision 37656)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrection.c	(revision 37657)
@@ -1,3 +1,4 @@
 # include "relastro.h"
+
 int FrameCorrectionWriteImageSH (FrameCorrectionType *frame, char *filename, int raDirection);
 
@@ -15,4 +16,23 @@
 
 */
+
+FrameCorrectionSet *FrameCorrectionSetInit () {
+
+  FrameCorrectionSet *set = NULL;
+  ALLOCATE (set, FrameCorrectionType, 1);
+
+  set->frame = NULL;
+  set->map = NULL;
+  return set;
+}
+
+void FrameCorrectionSetFree (FrameCorrectionSet *set) {
+
+  if (!set) return;
+
+  FrameCorrectionFree(set->frame);
+  AstromOffsetMapFree (set->map);
+  free set;
+}
 
 FrameCorrectionType *FrameCorrectionInit (double scale) {
Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrectionIO.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrectionIO.c	(revision 37657)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/FrameCorrectionIO.c	(revision 37657)
@@ -0,0 +1,181 @@
+# include "relastro.h"
+
+typedef struct {
+  AstromOffsetMap *map;
+  FrameCorrectionType *frame;
+} FrameCorrectionSet;
+
+// the frame correction consists of N image correction maps
+// there are local maps and AITOFF maps
+FrameCorrectionSet *FrameCorrectionLoad(char *filename) {
+
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  // FrameCorrectionSet consists:
+  // PHU header listing the contents:
+  // SHMAP_dR : EXTNAME or NONE
+  // SHMAP_dD : EXTNAME or NONE
+  // LOCAL_dR : EXTNAME or NONE
+  // LOCAL_dD : EXTNAME or NONE
+
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+
+  char SHMAP_DR[80], SHMAP_DD[80], LOCAL_DR[80], LOCAL_DD[80];
+  if (!gfits_scan (&header, "SHMAP_DR", "%s", 1, SHMAP_DR)) {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s missing required field SHMAP_DR\n", filename);
+    exit (2);
+  }
+  if (!gfits_scan (&header, "SHMAP_DD", "%s", 1, SHMAP_DD)) {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s missing required field SHMAP_DD\n", filename);
+    exit (2);
+  }
+  if (!gfits_scan (&header, "LOCAL_DR", "%s", 1, LOCAL_DR_)) {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s missing required field LOCAL_DR\n", filename);
+    exit (2);
+  }
+  if (!gfits_scan (&header, "LOCAL_DD", "%s", 1, LOCAL_DD)) {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s missing required field LOCAL_DD\n", filename);
+    exit (2);
+  }
+
+  Header Xheader;
+  if (strcmp(SHMAP_DR, "NONE")) {
+    if (!strcmp (SHMAP_DD, "NONE")) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s has defined SHMAP_DR but not SHMAP_DD\n", filename);
+      exit (2);
+    }
+    if (!gfits_find_Xheader(f, &Xheader, SHMAP_DR)) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s missing SHMAP_DR extension %s\n", filename, SHMAP_DR);
+      exit (2);
+    }
+    if (!gfits_fread_matrix (f, &matrix, &Xheader)) {
+      if (VERBOSE) fprintf (stderr, "can't read SHMAP_DR extension image\n");
+      gfits_free_header (&header);
+      fclose (f);
+      return NULL;
+    }
+    // convert image to frame
+    if (!gfits_find_Xheader(f, &Xheader, SHMAP_DD)) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s missing SHMAP_DD extension %s\n", filename, SHMAP_DD);
+      exit (2);
+    }
+    if (!gfits_fread_matrix (f, &matrix, &Xheader)) {
+      if (VERBOSE) fprintf (stderr, "can't read SHMAP_DD extension image\n");
+      gfits_free_header (&header);
+      fclose (f);
+      return NULL;
+    }
+  } else {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s has defined SHMAP_DD but not SHMAP_DR\n", filename);
+    exit (2);
+  }
+
+  if (strcmp(SHMAP_DR, "NONE")) {
+    if (!strcmp (SHMAP_DD, "NONE")) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s has defined SHMAP_DR but not SHMAP_DD\n", filename);
+      exit (2);
+    }
+    if (!gfits_find_Xheader(f, &Xheader, SHMAP_DR)) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s missing SHMAP_DR extension %s\n", filename, SHMAP_DR);
+      exit (2);
+    }
+    if (!gfits_fread_matrix (f, &matrix, &Xheader)) {
+      if (VERBOSE) fprintf (stderr, "can't read SHMAP_DR extension image\n");
+      gfits_free_header (&header);
+      fclose (f);
+      return NULL;
+    }
+    // convert image to frame
+    if (!gfits_find_Xheader(f, &Xheader, SHMAP_DD)) {
+      fprintf (stderr, "ERROR: FrameCorrectionSet %s missing SHMAP_DD extension %s\n", filename, SHMAP_DD);
+      exit (2);
+    }
+    if (!gfits_fread_matrix (f, &matrix, &Xheader)) {
+      if (VERBOSE) fprintf (stderr, "can't read SHMAP_DD extension image\n");
+      gfits_free_header (&header);
+      fclose (f);
+      return NULL;
+    }
+  } else {
+    fprintf (stderr, "ERROR: FrameCorrectionSet %s has defined SHMAP_DD but not SHMAP_DR\n", filename);
+    exit (2);
+  }
+}
+
+int FrameCorrectionSetSave(char *filename, FrameCorrectionSet *set) {
+
+  int i;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  gfits_init_header (&header);
+  header.extend = TRUE;
+  gfits_create_header (&header);
+  gfits_create_matrix (&header, &matrix);
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open meanmag file for output %s\n", filename);
+    return FALSE;
+  }
+
+  int status;
+  status = gfits_fwrite_header  (f, &header);
+  CHECK_STATUS (status, "ERROR: cannot write header for meanpos %s\n", filename);
+
+  status = gfits_fwrite_matrix  (f, &matrix);
+  CHECK_STATUS (status, "ERROR: cannot write matrix for meanpos %s\n", filename);
+
+  if (set->frame) {
+    gfits_modify (&header, "SHMAP_DR", "%s", "SHMAP_DR", 1);
+    gfits_modify (&header, "SHMAP_DD", "%s", "SHMAP_DD", 1);
+  status = gfits_fwrite_header  (f, &Xheader);
+  CHECK_STATUS (status, "ERROR: cannot write header for meanpos %s\n", filename);
+
+  status = gfits_fwrite_matrix  (f, &matrix);
+  CHECK_STATUS (status, "ERROR: cannot write matrix for meanpos %s\n", filename);
+  }
+  if (set->map) {
+    gfits_modify (&header, "LOCAL_DR", "%s", "LOCAL_DR", 1);
+    gfits_modify (&header, "LOCAL_DD", "%s", "LOCAL_DD", 1);
+  status = gfits_fwrite_header  (f, &Xheader);
+  CHECK_STATUS (status, "ERROR: cannot write header for meanpos %s\n", filename);
+
+  status = gfits_fwrite_matrix  (f, &matrix);
+  CHECK_STATUS (status, "ERROR: cannot write matrix for meanpos %s\n", filename);
+  }
+
+  // convert frame -> image
+  // convert map -> image
+
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+
+  int fd = fileno (f);
+
+  status = fflush (f);
+  CHECK_STATUS (!status, "ERROR: cannot flush file meanpos %s\n", filename);
+
+  status = fsync (fd);
+  CHECK_STATUS (!status, "ERROR: cannot flush file meanpos %s\n", filename);
+
+  status = fclose (f);
+  CHECK_STATUS (!status, "ERROR: problem closing meanpos file %s\n", filename);
+
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/ICRFobjIO.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/ICRFobjIO.c	(revision 37657)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/ICRFobjIO.c	(revision 37657)
@@ -0,0 +1,179 @@
+# include "relastro.h"
+
+# define GET_COLUMN(OUT,NAME,TYPE) \
+  TYPE *OUT = gfits_get_bintable_column_data (&theader, &ftable, NAME, type, &Nrow, &Ncol); \
+  myAssert (!strcmp(type, #TYPE), "wrong column type");
+
+// this is nearly identical to the one in 'uniphot/src' used by setphot / setphot_client.
+// Here, we use a handful of different columns (if not, we could move to libdvo)
+ICRFobj *ICRFobjLoad(char *filename, off_t *nicrfobj) {
+
+  int i, Ncol;
+  off_t Nrow;
+  Header header;
+  Header theader;
+  Matrix matrix;
+  FTable ftable;
+
+  *nicrfobj = 0;
+  ICRFobj *icrfobj = NULL;
+
+  FILE *f = fopen (filename, "r");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open image subset file %s\n", filename);
+    return NULL;
+  }
+
+  /* load in PHU segment (ignore) */
+  if (!gfits_fread_header (f, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+  if (!gfits_fread_matrix (f, &matrix, &header)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset matrix\n");
+    gfits_free_header (&header);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable.header = &theader;
+
+  // load data for this header 
+  if (!gfits_load_header (f, &theader)) {
+    fclose (f);
+    return NULL;
+  }
+
+  // read the fits table bytes
+  if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
+    fclose (f);
+    return (NULL);
+  }
+  fclose (f);
+
+  char type[16];
+
+  GET_COLUMN (R_AVE,   	 "R_AVE",          double);
+  GET_COLUMN (D_AVE,   	 "D_AVE",          double);
+  GET_COLUMN (R_MEAS,  	 "R_MEAS",         double);
+  GET_COLUMN (D_MEAS,  	 "D_MEAS",         double);
+
+  ALLOCATE (icrfobj, ICRFobj, Nrow);
+  for (i = 0; i < Nrow; i++) {
+    icrfobj[i].Rave           = Rave[i];
+    icrfobj[i].Dave           = Dave[i];
+    icrfobj[i].Rmeas          = Rmeas[i];
+    icrfobj[i].Dmeas          = Dmeas[i];
+  }
+  fprintf (stderr, "loaded data for %lld objects (* filters)\n", (long long) Nrow);
+
+  free (Rave );
+  free (Dave );
+  free (Rmeas);
+  free (Dmeas);
+
+  // free FITS table pieces...
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table  (&ftable);
+
+  *nicrfobj = Nrow;
+  return icrfobj;
+}
+
+// STATUS is value expected for success
+# define CHECK_STATUS(STATUS,MSG,...)					\
+  if (!(STATUS)) {							\
+    fprintf (stderr, MSG, __VA_ARGS__);					\
+    return FALSE;							\
+  }
+
+int ICRFobjSave(char *filename, ICRFobj *icrfobj, off_t Nicrfobj) {
+
+  int i;
+  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", "ICRFOBJ");
+
+  gfits_define_bintable_column (&theader, "D", "R_AVE",       "mean position, ra",  "degrees", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "D_AVE",       "mean position, dec", "degrees", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "R_MEAS",      "meas position, ra",  "degrees", 1.0, 0.0);
+  gfits_define_bintable_column (&theader, "D", "D_MEAS",      "meas position, dec", "degrees", 1.0, 0.0);
+
+  // generate the output array that carries the data
+  gfits_create_table (&theader, &ftable);
+
+  double *Rave, *Dave, *Rmeas, *Dmeas;
+
+  // create intermediate storage arrays
+  ALLOCATE (Rave ,         double, 	       Nicrfobj);
+  ALLOCATE (Dave ,         double, 	       Nicrfobj);
+  ALLOCATE (Rmeas,         double, 	       Nicrfobj);
+  ALLOCATE (Dmeas,         double, 	       Nicrfobj);
+
+  // assign the storage arrays
+  for (i = 0; i < Nicrfobj; i++) {
+    Rave [i]   = icrfobj[i].Rave ;
+    Dave [i]   = icrfobj[i].Dave ;
+    Rmeas[i]   = icrfobj[i].Rmeas;
+    Dmeas[i]   = icrfobj[i].Dmeas;
+  }
+
+  // add the columns to the output array
+  gfits_set_bintable_column (&theader, &ftable, "R_AVE",        Rave ,         Nicrfobj);
+  gfits_set_bintable_column (&theader, &ftable, "D_AVE",        Dave ,         Nicrfobj);
+  gfits_set_bintable_column (&theader, &ftable, "R_MEAS",       Rmeas,         Nicrfobj);
+  gfits_set_bintable_column (&theader, &ftable, "D_MEAS",       Dmeas,         Nicrfobj);
+
+  free (Rave     );
+  free (Dave     );
+  free (Rmeas    );
+  free (Dmeas    );
+
+  FILE *f = fopen (filename, "w");
+  if (!f) {
+    fprintf (stderr, "ERROR: cannot open meanmag file for output %s\n", filename);
+    return FALSE;
+  }
+
+  int status;
+  status = gfits_fwrite_header  (f, &header);
+  CHECK_STATUS (status, "ERROR: cannot write header for icrfobj %s\n", filename);
+
+  status = gfits_fwrite_matrix  (f, &matrix);
+  CHECK_STATUS (status, "ERROR: cannot write matrix for icrfobj %s\n", filename);
+
+  status = gfits_fwrite_Theader (f, &theader);
+  CHECK_STATUS (status, "ERROR: cannot write table header for icrfobj %s\n", filename);
+
+  status = gfits_fwrite_table  (f, &ftable);
+  CHECK_STATUS (status, "ERROR: cannot write table data for icrfobj %s\n", filename);
+
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
+  int fd = fileno (f);
+
+  status = fflush (f);
+  CHECK_STATUS (!status, "ERROR: cannot flush file icrfobj %s\n", filename);
+
+  status = fsync (fd);
+  CHECK_STATUS (!status, "ERROR: cannot fsync file icrfobj %s\n", filename);
+
+  status = fclose (f);
+  CHECK_STATUS (!status, "ERROR: problem closing icrfobj file %s\n", filename);
+
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/load_catalogs.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/load_catalogs.c	(revision 37656)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/load_catalogs.c	(revision 37657)
@@ -171,4 +171,6 @@
     if (FlagOutlier)   strextend (command, "-clip %d", CLIP_THRESH);
     if (ExcludeBogus)  strextend (command, "-exclude-bogus %f", ExcludeBogusRadius);
+    if (USE_ICRF_CORRECT) strextend (command, "-D USE_ICRF_CORRECT %d", USE_ICRF_CORRECT);
+    if (USE_GALAXY_MODEL) strextend (command, "-D USE_GALAXY_MODEL %d", USE_GALAXY_MODEL);
     
     if (DCR_BLUE_COLOR_POS && DCR_BLUE_COLOR_NEG) {
Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/relastro_parallel_images.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/relastro_parallel_images.c	(revision 37656)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/relastro_parallel_images.c	(revision 37657)
@@ -88,4 +88,6 @@
       for (i = 0; i < NLOOP; i++) {
 	UpdateObjects (catalog, Ncatalog, (i > 0));
+	share_icrf_obj (catalog, Ncatalog, regionHosts, i); 
+	applyFrameCorr (catalog, Ncatalog, regionHosts, i); // read and apply the frame correction
 	share_mean_pos (catalog, Ncatalog, regionHosts, i);
 	// XXX FrameCorrection (catalog, Ncatalog); -- this needs to happen on the master machine?
Index: /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/share_icrf_obj.c
===================================================================
--- /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/share_icrf_obj.c	(revision 37657)
+++ /branches/eam_branches/ipp-20140904/Ohana/src/relastro/src/share_icrf_obj.c	(revision 37657)
@@ -0,0 +1,92 @@
+# include "relastro.h"
+
+// we are sharing mean and specific positions for all known ICRF objects which I own
+// this function occurs on the remote hosts in parallel-region processing
+int share_icrf_obj (Catalog *catalog, int Ncatalog, RegionHostTable *regionHosts, int nloop) {
+
+  if (!USE_ICRF_CORRECT) return TRUE;
+
+  int Nicrf = ICRFmax();
+
+  // we need to write an empty table none are available
+  ICRFobj *icrfobj = NULL;
+  ALLOCATE (icrfobj, ICRFobj, Nicrf);
+
+  // select the ICRF QSOS and save the necessary data
+  for (i = 0; i < Nicrf; i++) {
+
+    int cat, ave, meas;
+    ICRFdata (i, &cat, &ave, &meas);
+
+    Average *average = &catalog[cat].average[ave];
+    MeasureTiny *measure = &catalog[cat].measureT[meas]; // MeasureTiny?
+
+    icrfobj[i].Rave  = average->R;
+    icrfobj[i].Dave  = average->D;
+    icrfobj[i].Rmeas = measure->R;
+    icrfobj[i].Rmeas = measure->R;
+  }
+
+  char *filename = make_filename (CATDIR, hostname, REGION_HOST_ID, "icrfobj.fits");
+  ICRFobjSave (filename, icrfobj, Nicrf);
+  free (icrfobj);
+  free (filename);
+
+  char *syncfile = make_filename (CATDIR, hostname, REGION_HOST_ID, "icrfobj.sync");
+  update_sync_file (syncfile, nloop);
+  free (syncfile);
+
+  return TRUE;
+}
+
+// load mean and specific positions for all known ICRF objects from remote hosts.
+// this function occurs on the master host in parallel-region processing
+int slurp_icrf_obj (RegionHostTable *regionHosts, int nloop) {
+
+  off_t i;
+
+  int Nicrfobj = 0;
+  ICRFobj *icrfobj = NULL;
+  ALLOCATE (icrfobj, ICRFobj, 1);
+
+  fprintf (stderr, "grabbing icrf objects from remote hosts...\n");
+
+  for (i = 0; i < regionHosts->Nhosts; i++) {
+    char *syncfile = make_filename (CATDIR, regionHosts->hosts[i].hostname, regionHosts->hosts[i].hostID, "icrfobj.sync");
+    check_sync_file (syncfile, nloop);
+    free (syncfile);
+    
+    off_t Nsubset = 0;
+    char *filename = make_filename (CATDIR, regionHosts->hosts[i].hostname, regionHosts->hosts[i].hostID, "icrfobj.fits");
+    ICRFobj *icrfobjSubset = ICRFobjLoad (filename, &Nsubset);
+    free (filename);
+
+    // merge_mean_pos reallocs icrfobj and frees the input icrfobjSubset
+    icrfobj = merge_icrf_obj (icrfobj, &Nicrfobj, icrfobjSubset, Nsubset);
+  }
+
+  frame_correction_icrfobj ();
+
+  save_frame_correction ();
+
+  free (icrfobj);
+
+  fprintf (stderr, "DONE grabbing mean object pos from other hosts...\n");
+
+  return TRUE;
+}
+
+ICRFobj *merge_icrf_obj (ICRFobj *target, int *ntarget, ICRFobj *source, int Nsource) {
+
+  off_t i;
+
+  REALLOCATE (target, ICRFobj, *ntarget + Nsource);
+  for (i = 0; i < Nsource; i++) {
+    off_t n = i + *ntarget;
+    target[n] = source[i];
+  }
+  free (source);
+
+  *ntarget += Nsource;
+  return (target);
+}
