Index: trunk/Ohana/src/uniphot/Makefile
===================================================================
--- trunk/Ohana/src/uniphot/Makefile	(revision 38463)
+++ trunk/Ohana/src/uniphot/Makefile	(revision 38464)
@@ -112,8 +112,10 @@
 $(SRC)/setastrom.$(ARCH).o	    \
 $(SRC)/initialize_setastrom.$(ARCH).o \
+$(SRC)/tyc_correction.$(ARCH).o \
 $(SRC)/cam_correction.$(ARCH).o \
 $(SRC)/dcr_correction.$(ARCH).o \
 $(SRC)/kh_correction.$(ARCH).o \
 $(SRC)/astrom_correction.$(ARCH).o \
+$(SRC)/repair_tycho_setastrom.$(ARCH).o \
 $(SRC)/update_dvo_setastrom.$(ARCH).o \
 $(SRC)/update_catalog_setastrom.$(ARCH).o \
@@ -128,7 +130,9 @@
 $(SRC)/update_dvo_setastrom.$(ARCH).o \
 $(SRC)/update_catalog_setastrom.$(ARCH).o \
+$(SRC)/tyc_correction.$(ARCH).o \
 $(SRC)/cam_correction.$(ARCH).o \
 $(SRC)/dcr_correction.$(ARCH).o \
 $(SRC)/kh_correction.$(ARCH).o \
+$(SRC)/repair_tycho_setastrom.$(ARCH).o \
 $(SRC)/astrom_correction.$(ARCH).o \
 $(SRC)/initialize_setastrom.$(ARCH).o
Index: trunk/Ohana/src/uniphot/include/setastrom.h
===================================================================
--- trunk/Ohana/src/uniphot/include/setastrom.h	(revision 38463)
+++ trunk/Ohana/src/uniphot/include/setastrom.h	(revision 38464)
@@ -49,8 +49,10 @@
 char        *DCR_FILE;
 char        *CAM_FILE;
+char        *TYC_FILE;
 
 int          KH_RESET;
 int          DCR_RESET;
 int          CAM_RESET;
+int          TYC_RESET;
 
 SkyRegion    UserPatch;
@@ -91,2 +93,6 @@
 int load_cam_correction (char *filename);
 int get_cam_correction (int chipID, int filter, float Xccd, float Yccd, double *dX, double *dY);
+
+int load_tyc_correction (char *filename);
+int get_tyc_correction (double **R, double **D, int *N);
+int repair_tycho_setastrom (Catalog *catalog, SkyRegion *region);
Index: trunk/Ohana/src/uniphot/src/initialize_setastrom.c
===================================================================
--- trunk/Ohana/src/uniphot/src/initialize_setastrom.c	(revision 38463)
+++ trunk/Ohana/src/uniphot/src/initialize_setastrom.c	(revision 38464)
@@ -7,4 +7,5 @@
     fprintf (stderr, "    -DCR (file) : supply DCR correction splines\n");
     fprintf (stderr, "    -CAM (file) : supply camera-static correction file\n");
+    fprintf (stderr, "    -TYC (file) : supply tycho-fix file (no pm stars)\n");
     fprintf (stderr, "    -v : verbose mode\n");
     fprintf (stderr, "    -region Rmin Rmax Dmin Dmax\n");
@@ -91,4 +92,17 @@
   }
 
+  TYC_FILE = NULL;
+  if ((N = get_argument (argc, argv, "-TYC"))) {
+    remove_argument (N, &argc, argv);
+    char *tmpfile = strcreate (argv[N]);
+    TYC_FILE = abspath (tmpfile, DVO_MAX_PATH);
+    remove_argument (N, &argc, argv);
+  }
+  TYC_RESET = FALSE;
+  if ((N = get_argument (argc, argv, "-TYC-reset"))) {
+    remove_argument (N, &argc, argv);
+    TYC_RESET = TRUE;
+  }
+
   SINGLE_CPT = NULL;
   if ((N = get_argument (argc, argv, "-cpt"))) {
@@ -160,6 +174,6 @@
   }
 
-  if (!KH_FILE && !DCR_FILE && !CAM_FILE) {
-    fprintf (stderr, "WARNING: none of -CAM, -KH, -DCR supplied\n");
+  if (!KH_FILE && !DCR_FILE && !CAM_FILE && !TYC_FILE) {
+    fprintf (stderr, "WARNING: none of -CAM, -KH, -DCR, -TYC supplied\n");
   }
 
@@ -175,4 +189,5 @@
   fprintf (stderr, "    -DCR (file) : supply DCR correction splines\n");
   fprintf (stderr, "    -CAM (file) : supply camera-static correction file\n");
+  fprintf (stderr, "    -TYC (file) : supply tycho-fix file (no pm stars)\n");
   fprintf (stderr, "    -region Rmin Rmax Dmin Dmax\n");
   fprintf (stderr, "    -update-catformat (format) : change database schema on output\n");
@@ -247,4 +262,17 @@
     remove_argument (N, &argc, argv);
     CAM_RESET = TRUE;
+  }
+
+  TYC_FILE = NULL;
+  if ((N = get_argument (argc, argv, "-TYC"))) {
+    remove_argument (N, &argc, argv);
+    char *tmpfile = strcreate (argv[N]);
+    TYC_FILE = abspath (tmpfile, DVO_MAX_PATH);
+    remove_argument (N, &argc, argv);
+  }
+  TYC_RESET = FALSE;
+  if ((N = get_argument (argc, argv, "-TYC-reset"))) {
+    remove_argument (N, &argc, argv);
+    TYC_RESET = TRUE;
   }
 
@@ -308,6 +336,6 @@
   if (!CATDIR) usage_setastrom_client();
 
-  if (!KH_FILE && !DCR_FILE && !CAM_FILE) {
-    fprintf (stderr, "WARNING: none of -CAM, -KH, -DCR supplied\n");
+  if (!KH_FILE && !DCR_FILE && !CAM_FILE && !TYC_FILE) {
+    fprintf (stderr, "WARNING: none of -CAM, -KH, -DCR, -TYC supplied\n");
   }
 
Index: trunk/Ohana/src/uniphot/src/repair_tycho_setastrom.c
===================================================================
--- trunk/Ohana/src/uniphot/src/repair_tycho_setastrom.c	(revision 38464)
+++ trunk/Ohana/src/uniphot/src/repair_tycho_setastrom.c	(revision 38464)
@@ -0,0 +1,133 @@
+# include "setastrom.h"
+
+int repair_tycho_setastrom (Catalog *catalog, SkyRegion *region) {
+
+  double *tychoR, *tychoD;
+  int Ntycho;
+
+  short TYCHO_B = GetPhotcodeCodebyName ("TYCHO_B"); myAssert (TYCHO_B, "TYCHO_B photcode not found\n");
+  short TYCHO_V = GetPhotcodeCodebyName ("TYCHO_V"); myAssert (TYCHO_V, "TYCHO_V photcode not found\n");
+
+  // the tycho R,D entries are sorted by tychoR
+  if (!get_tyc_correction (&tychoR, &tychoD, &Ntycho)) {
+    fprintf (stderr, "TYCHO correction not loaded\n");
+    exit (2);
+  }
+
+  // first select the subset of objects which lie in this catalog:
+  int Ns = ohana_bisection_double (tychoR, Ntycho, region->Rmin);
+  Ns = MAX(Ns, 0); // if Rmin = 0.0, Ns could be -1 (since there are no entries with R < 0.0
+
+  int NSUBSET = 100;
+  int Nsubset = 0;
+  int *index = NULL;
+  ALLOCATE (index, int, NSUBSET);
+
+  // scan through tycho stars to select those in this catalog
+  while ((Ns < Ntycho) && (tychoR[Ns] < region->Rmax)) {
+    if (tychoD[Ns] < region->Dmin) continue;
+    if (tychoD[Ns] > region->Dmax) continue;
+    // we have an object in range (Rmin <= R < Rmax; Dmin <= D <= Dmax)
+
+    index[Nsubset] = Ns;
+    Nsubset ++;
+    CHECK_REALLOCATE (index, int, NSUBSET, Nsubset, 100);
+  }  
+  if (Nsubset == 0) {
+    free (index);
+    return TRUE;
+  }
+  
+  // now find matches within this catalog
+  
+  /** allocate local arrays (stars) **/
+  off_t *N1, *N2;
+  double *X1, *Y1, *X2, *Y2;
+  ALLOCATE (X1, double, Nsubset);
+  ALLOCATE (Y1, double, Nsubset);
+  ALLOCATE (N1, off_t,  Nsubset);
+
+  /** allocate local arrays (catalog) **/
+  ALLOCATE (X2, double, catalog[0].Naverage);
+  ALLOCATE (Y2, double, catalog[0].Naverage);
+  ALLOCATE (N2, off_t,  catalog[0].Naverage);
+
+  Coords tcoords;
+  InitCoords (&tcoords, "DEC--ARC");
+  tcoords.crval1 = 0.5*(region[0].Rmin + region[0].Rmax);
+  if (region[0].Dmax < 90) {
+    tcoords.crval2 = 0.5*(region[0].Dmin + region[0].Dmax);
+  } else {
+    tcoords.crval2 = 90.0;
+  }
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+
+  /* build spatial index (RA sort) referencing input array sequence */
+  int i, j, J, k;
+  for (i = 0; i < Nsubset; i++) {
+    RD_to_XY (&X1[i], &Y1[i], tychoR[index[i]], tychoD[index[i]], &tcoords);
+    N1[i] = i;
+  }
+  sort_coords_index (X1, Y1, N1, Nsubset);
+  
+  /* build spatial index (RA sort) */
+  for (i = 0; i < catalog[0].Naverage; i++) {
+    RD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    N2[i] = i;
+  }
+  sort_coords_index (X2, Y2, N2, catalog[0].Naverage);
+
+    /* choose a radius for matches (defined in args.c or ImageOptions.c) */
+  float RADIUS = 1.0;
+  float RADIUS2 = RADIUS*RADIUS;
+
+  float dX, dY, dR;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nsubset) && (j < catalog[0].Naverage); ) {
+    if (!finite(X1[i]) || !finite(Y1[i])) { i++; continue; }
+    if (!finite(X2[j]) || !finite(Y2[j])) { j++; continue; }
+
+    /* negative dX: j is too large; positive dX, i is too large */
+    dX = X1[i] - X2[j];
+    if (dX <= -1.02*RADIUS) { i++; continue; }
+    if (dX >= +1.02*RADIUS) { j++; continue; }
+
+    /* within match range; look for matches */
+    for (J = j; (dX > -1.02*RADIUS) && (J < catalog[0].Naverage); J++) {
+      dX = X1[i] - X2[J];
+      dY = Y1[i] - Y2[J];
+      dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+
+      /*** a match is found ***/
+
+      off_t Ns = N1[i];
+      off_t Nc = N2[j];
+
+      off_t m = catalog[0].average[Nc].measureOffset;
+
+      // for these stars, the average.R,D values are correct; replace the measure.R,D
+      for (k = 0; k < catalog[0].average[Nc].Nmeasure; k++) {
+	// find the tycho photcodes:
+	int valid = FALSE;
+	valid = valid || (catalog[0].measure[m+k].photcode == TYCHO_B);
+	valid = valid || (catalog[0].measure[m+k].photcode == TYCHO_V);
+	if (!valid) continue;
+	catalog[0].measure[m+k].R = tychoR[Ns];
+	catalog[0].measure[m+k].D = tychoD[Ns];
+      }
+    }
+  }
+  
+  free (X1);
+  free (X2);
+  free (Y1);
+  free (Y2);
+  free (N1);
+  free (N2);
+  free (index);
+
+  return TRUE;
+}
+
Index: trunk/Ohana/src/uniphot/src/setastrom.c
===================================================================
--- trunk/Ohana/src/uniphot/src/setastrom.c	(revision 38463)
+++ trunk/Ohana/src/uniphot/src/setastrom.c	(revision 38464)
@@ -8,6 +8,5 @@
   initialize_setastrom (argc, argv);
 
-  // argv[1] holds the correction file
-  status = update_dvo_setastrom (argv[1]);
+  status = update_dvo_setastrom ();
 
   if (!status) exit (1);
Index: trunk/Ohana/src/uniphot/src/setphot.c
===================================================================
--- trunk/Ohana/src/uniphot/src/setphot.c	(revision 38463)
+++ trunk/Ohana/src/uniphot/src/setphot.c	(revision 38464)
@@ -21,4 +21,5 @@
   if (UBERCAL) {
     zpts = load_zpt_ubercal (argv[1], &Nzpts, &flatcorrTable);
+    if (!zpts) Shutdown ("failed to load zero points from ubercal table");
 
     char flatcorrfile[DVO_MAX_PATH];
Index: trunk/Ohana/src/uniphot/src/tyc_correction.c
===================================================================
--- trunk/Ohana/src/uniphot/src/tyc_correction.c	(revision 38464)
+++ trunk/Ohana/src/uniphot/src/tyc_correction.c	(revision 38464)
@@ -0,0 +1,48 @@
+# include "setastrom.h"
+
+static int Ntycho = 0;
+static double *tychoR = NULL;
+static double *tychoD = NULL;
+
+// the tycho correction table just lists the tycho stars (R,D) for which the astrometry was messed up
+int load_tyc_correction (char *filename) {
+
+  FILE *f = fopen (filename, "r");
+  if (!f) myAbort ("file not found");
+
+  double *tychoR, *tychoD;
+
+  int NTYCHO = 10000;
+
+  ALLOCATE (tychoR, double, NTYCHO);
+  ALLOCATE (tychoD, double, NTYCHO);
+
+  while (fscanf (f, "%lf %lf", &tychoR[Ntycho], &tychoD[Ntycho]) != EOF) {
+    Ntycho ++;
+
+    if (Ntycho >= NTYCHO) {
+      NTYCHO += 10000;
+      REALLOCATE (tychoR, double, NTYCHO);
+      REALLOCATE (tychoD, double, NTYCHO);
+    }
+  }
+
+  dsortpair (tychoR, tychoD, Ntycho); 
+
+  return TRUE;
+}
+
+int get_tyc_correction (double **R, double **D, int *N) {
+
+  *R = NULL;
+  *D = NULL;
+  *N = 0;
+
+  if (!tychoR) return FALSE;
+
+  *R = tychoR;
+  *D = tychoD;
+  *N = Ntycho;
+  return TRUE;
+}
+
Index: trunk/Ohana/src/uniphot/src/update_dvo_setastrom.c
===================================================================
--- trunk/Ohana/src/uniphot/src/update_dvo_setastrom.c	(revision 38463)
+++ trunk/Ohana/src/uniphot/src/update_dvo_setastrom.c	(revision 38464)
@@ -20,4 +20,5 @@
   if (DCR_FILE) if (!load_dcr_correction (DCR_FILE)) { fprintf (stderr, "failed to load DCR correction %s\n", DCR_FILE); exit (1); }
   if (CAM_FILE) if (!load_cam_correction (CAM_FILE)) { fprintf (stderr, "failed to load CAM correction %s\n", CAM_FILE); exit (1); }
+  if (TYC_FILE) if (!load_tyc_correction (TYC_FILE)) { fprintf (stderr, "failed to load TYC correction %s\n", TYC_FILE); exit (1); }
 
   // determine the populated SkyRegions overlapping the requested area (default depth)
@@ -56,4 +57,7 @@
     }
 
+    if (TYC_FILE) {
+      repair_tycho_setastrom (&catalog, skylist[0].regions[i]);
+    }
     update_catalog_setastrom (&catalog);
 
