IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 37261


Ignore:
Timestamp:
Aug 14, 2014, 2:25:44 PM (12 years ago)
Author:
eugene
Message:

fix stack R,D in relastro

Location:
trunk/Ohana/src/relastro
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Ohana/src/relastro/Makefile

    r36833 r37261  
    5959$(SRC)/save_catalogs.$(ARCH).o       \
    6060$(SRC)/CoordOps.$(ARCH).o            \
     61$(SRC)/extra.$(ARCH).o            \
    6162$(SRC)/FixProblemImages.$(ARCH).o    \
    6263$(SRC)/StarMaps.$(ARCH).o    \
     
    117118$(SRC)/save_catalogs.$(ARCH).o       \
    118119$(SRC)/CoordOps.$(ARCH).o            \
     120$(SRC)/extra.$(ARCH).o            \
    119121$(SRC)/high_speed_catalogs.$(ARCH).o  \
    120122$(SRC)/high_speed_objects.$(ARCH).o  \
  • trunk/Ohana/src/relastro/include/relastro.h

    r37038 r37261  
    133133  int    Nmeas;
    134134} StatType;
     135
     136typedef struct {
     137  off_t Nave;
     138  off_t Npm;
     139  off_t Npar;
     140  off_t Nskip;
     141  off_t Noffset;
     142} FitStats;
    135143
    136144/* global variables set in parameter file */
     
    535543int areImagesLoaded ();
    536544int areImagesMatched ();
     545
     546int isGPC1chip (int photcode);
     547int isGPC1stack (int photcode);
     548int isGPC1warp (int photcode);
  • trunk/Ohana/src/relastro/src/ParFactor.c

    r33652 r37261  
    6363  double jd, lambda, beta, epsilon, Radius;
    6464
    65   /* given a time T in UNIX seconds, determine the solar longitude S */
     65  /* given a Time relative to Tmean, Tmean in years since J2000, determine the solar
     66    longitude S */
    6667
    6768  // jd = ohana_sec_to_jd (365.25*86400.0*(Time + Tmean));
  • trunk/Ohana/src/relastro/src/UpdateObjects.c

    r37246 r37261  
    11# include "relastro.h"
     2# define PAR_TOOFEW 5
     3
     4int UpdateObjects_Chips (Average *average, SecFilt *secfilt, MeasureTiny *measure, Measure *measureBig, int Nsecfilt, FitStats *fitStats, int i, off_t m);
     5int UpdateObjects_Stack (Average *average, SecFilt *secfilt, MeasureTiny *measure, Measure *measureBig, int Nsecfilt, FitStats *fitStats);
    26
    37static off_t Nmax;
     
    1317static double *C_red;
    1418
     19static Coords coords;
     20
     21static time_t T2000;
     22
     23void initFitStats (FitStats *fitStats) {
     24  fitStats->Nave = 0; 
     25  fitStats->Npm = 0;   
     26  fitStats->Npar = 0; 
     27  fitStats->Nskip = 0;
     28  fitStats->Noffset = 0;
     29  return;
     30}
     31
     32void sumFitStats (FitStats *srcFitStats, FitStats *tgtFitStats) {
     33  tgtFitStats->Nave    += srcFitStats->Nave    ; 
     34  tgtFitStats->Npm     += srcFitStats->Npm     ;   
     35  tgtFitStats->Npar    += srcFitStats->Npar    ; 
     36  tgtFitStats->Nskip   += srcFitStats->Nskip   ;
     37  tgtFitStats->Noffset += srcFitStats->Noffset ;
     38  return;
     39}
     40
    1541void initObjectData (Catalog *catalog, int Ncatalog) {
    1642
     
    4167  ALLOCATE (C_blue, double, MAX (1, Nmax));
    4268  ALLOCATE (C_red,  double, MAX (1, Nmax));
    43 
    44 
    45 void freeObjectData () {
    46 
    47   free (R);
    48   free (D);
    49   free (T);
    50   free (X);
    51   free (Y);
    52 
    53   free (dR);
    54   free (dD);
    55   free (dT);
    56   free (dX);
    57   free (dY);
    58 
    59   free (pX);
    60   free (pY);
    61 
    62   free (C_blue);
    63   free (C_red);
    64 
    65 
    66 // This function operates on both Measure and MeasureTiny.  In the big stages, this should
    67 // be called with just MeasureTiny set and Measure == NULL
    68 int UpdateObjects (Catalog *catalog, int Ncatalog) {
    69 
    70   off_t j, k, m;
    71   int i, N, NcBlue, NcRed, Nsecfilt, mode, result, status, XVERB;
    72   StatType statsR, statsD;
    73   Coords coords;
    74   PMFit fitAve, fitPM, fitPAR, fit;
    75   time_t T2000;
    76   off_t Nave, Npm, Npar, Nskip, Noffset;
    77   off_t NaveSum, NpmSum, NparSum, NskipSum, NoffSum;
    78   double Tmin, Tmax, Tmean, Trange;
    79 
    80   memset (&fit,    0, sizeof(fit));
    81   memset (&fitAve, 0, sizeof(fitAve));
    82   memset (&fitPM,  0, sizeof(fitPM));
    83   memset (&fitPAR, 0, sizeof(fitPAR));
    84   initObjectData (catalog, Ncatalog);
    85 
    86   int setRefColor = areImagesMatched();
    8769
    8870  /* project coordinates to a plane centered on the object with units of arcsec */
     
    9779  strcpy (coords.ctype, "DEC--SIN");
    9880
    99   XVERB = FALSE;
    100 
    10181  // use J2000 as a reference time
    102   T2000 = ohana_date_to_sec ("2000/01/01");
     82  T2000 = ohana_date_to_sec ("2000/01/01,12:00:00");
     83
     84
     85void freeObjectData () {
     86
     87  free (R);
     88  free (D);
     89  free (T);
     90  free (X);
     91  free (Y);
     92
     93  free (dR);
     94  free (dD);
     95  free (dT);
     96  free (dX);
     97  free (dY);
     98
     99  free (pX);
     100  free (pY);
     101
     102  free (C_blue);
     103  free (C_red);
     104
     105
     106// This function operates on both Measure and MeasureTiny.  In the big stages, this should
     107// be called with just MeasureTiny set and Measure == NULL
     108int UpdateObjects (Catalog *catalog, int Ncatalog) {
     109
     110  initObjectData (catalog, Ncatalog);
     111
    103112  // XXX in the future, use catalog[0].Nsecfilt only?  allow catalogs to have variable Nsecfilt?
    104 
    105   Nsecfilt = GetPhotcodeNsecfilt ();
     113  int Nsecfilt = GetPhotcodeNsecfilt ();
    106114  if (Ncatalog) {
    107115    assert (catalog[0].Nsecfilt == Nsecfilt);
    108116  }
    109117
    110   NaveSum = NparSum = NpmSum = NoffSum = NskipSum = 0;
     118  FitStats sumStatsChips; initFitStats (&sumStatsChips);
     119  FitStats sumStatsStack; initFitStats (&sumStatsStack);
     120
     121  int i;
    111122  for (i = 0; i < Ncatalog; i++) {
    112123
    113124    if (VERBOSE2) fprintf (stderr, "astrometrize catalog %d : "OFF_T_FMT" ave, "OFF_T_FMT" meas\n", i,  catalog[i].Naverage,  catalog[i].Nmeasure);
    114125
    115     Nave = Npar = Npm = Nskip = Noffset = 0;
     126    FitStats fitStatsChips; initFitStats (&fitStatsChips);
     127    FitStats fitStatsStack; initFitStats (&fitStatsStack);
     128
     129    off_t j;
    116130    for (j = 0; j < catalog[i].Naverage; j++) {
    117131      /* calculate the average value of R,D for a single star */
    118 
    119       XVERB = FALSE;
    120       fitAve.chisq = NAN;
    121       fitPM.chisq = NAN;
    122       fitPAR.chisq = NAN;
    123 
    124       // if we fail to fit the astrometry for some reason, we need to set/reset these
    125       catalog[i].average[j].flags |= ID_STAR_NO_ASTROM;
    126       catalog[i].average[j].ChiSqAve  = NAN;
    127       catalog[i].average[j].ChiSqPM   = NAN;
    128       catalog[i].average[j].ChiSqPar  = NAN;
    129       catalog[i].average[j].Npos = 0;
    130 
    131       if (catalog[i].average[j].Nmeasure == 0) {
     132      off_t m = catalog[i].average[j].measureOffset;
     133      MeasureTiny *measure = &catalog[i].measureT[m];
     134      Measure *measureBig = catalog[i].measure ? &catalog[i].measure[m] : NULL;
     135      Average *average = &catalog[i].average[j];
     136      SecFilt *secfilt = &catalog[i].secfilt[j*Nsecfilt];
     137
     138      UpdateObjects_Stack(average, secfilt, measure, measureBig, Nsecfilt, &fitStatsStack);
     139      UpdateObjects_Chips(average, secfilt, measure, measureBig, Nsecfilt, &fitStatsChips, i, m);
     140    }
     141    if (VERBOSE) fprintf (stderr, "catalog %d : chips "OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par : Nskip "OFF_T_FMT", Noffset "OFF_T_FMT"\n",  i,  fitStatsChips.Nave,  fitStatsChips.Npm,  fitStatsChips.Npar,  fitStatsChips.Nskip, fitStatsChips.Noffset);
     142    if (VERBOSE) fprintf (stderr, "catalog %d : stack "OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par : Nskip "OFF_T_FMT", Noffset "OFF_T_FMT"\n",  i,  fitStatsStack.Nave,  fitStatsStack.Npm,  fitStatsStack.Npar,  fitStatsStack.Nskip, fitStatsStack.Noffset);
     143    sumFitStats (&fitStatsChips, &sumStatsChips);
     144    sumFitStats (&fitStatsStack, &sumStatsStack);
     145  }
     146  freeObjectData ();
     147
     148  if (VERBOSE) fprintf (stderr, "fitted "OFF_T_FMT" objects ("OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par), skipped "OFF_T_FMT", "OFF_T_FMT" have too large an offset\n",  (sumStatsChips.Nave + sumStatsChips.Npm + sumStatsChips.Npar),  sumStatsChips.Nave,  sumStatsChips.Npm,  sumStatsChips.Npar,  sumStatsChips.Nskip, sumStatsChips.Noffset);
     149  if (VERBOSE) fprintf (stderr, "fitted "OFF_T_FMT" objects ("OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par), skipped "OFF_T_FMT", "OFF_T_FMT" have too large an offset\n",  (sumStatsStack.Nave + sumStatsStack.Npm + sumStatsStack.Npar),  sumStatsStack.Nave,  sumStatsStack.Npm,  sumStatsStack.Npar,  sumStatsStack.Nskip, sumStatsStack.Noffset);
     150  return (TRUE);
     151}
     152
     153// This function operates on both Measure and MeasureTiny.  In the big stages, this should
     154// be called with just MeasureTiny set and Measure == NULL
     155int UpdateObjects_Chips (Average *average, SecFilt *secfilt, MeasureTiny *measure, Measure *measureBig, int Nsecfilt, FitStats *fitStats, int i, off_t m) {
     156
     157  int setRefColor = areImagesMatched();
     158
     159  /* calculate the average value of R,D for a single star */
     160
     161  PMFit fit;    memset (&fit,    0, sizeof(fit));
     162  PMFit fitAve; memset (&fitAve, 0, sizeof(fitAve)); fitAve.chisq = NAN;
     163  PMFit fitPM;  memset (&fitPM,  0, sizeof(fitPM));  fitPM.chisq = NAN;
     164  PMFit fitPAR; memset (&fitPAR, 0, sizeof(fitPAR)); fitPAR.chisq = NAN;
     165
     166  // if we fail to fit the astrometry for some reason, we need to set/reset these
     167  average[0].flags |= ID_STAR_NO_ASTROM;
     168  average[0].ChiSqAve  = NAN;
     169  average[0].ChiSqPM   = NAN;
     170  average[0].ChiSqPar  = NAN;
     171  average[0].Npos = 0;
     172
     173  // an object with no measurements is externally supplied
     174  if (average[0].Nmeasure == 0) return TRUE;
     175
     176  int NcBlue = 0;
     177  int NcRed = 0;
     178  int N = 0;
     179
     180  int mode = FIT_MODE; // start with the globally-defined fit mode
     181
     182  int XVERB = FALSE;
     183  XVERB |= (average[0].objID == OBJ_ID_SRC) && (average[0].catID == CAT_ID_SRC);
     184  XVERB |= (average[0].objID == OBJ_ID_DST) && (average[0].catID == CAT_ID_DST);
     185
     186  // find the basic properties of the detections for this object (Tmin, Tmax, Tmean)
     187  off_t k;
     188  for (k = 0; k < average[0].Nmeasure; k++) {
     189
     190    if (XVERB) {
     191      char *date = ohana_sec_to_date (measure[k].t);
     192      int dbFlagsBig = measureBig ? measureBig[k].dbFlags : 0;
     193      fprintf (stderr, OFF_T_FMT" %f %f %s : 0x%08x : 0x%08x\n",  k, measure[k].R, measure[k].D, date, measure[k].dbFlags, dbFlagsBig);
     194      free (date);
     195    }
     196
     197    // SKIP gpc1 stack data
     198    if (isGPC1stack(measure[k].photcode)) continue;
     199
     200    // SKIP gpc1 forced-warp data
     201    if (isGPC1warp(measure[k].photcode)) continue;
     202
     203    // reset the bit to note that a detection was used (or not)
     204    measure[k].dbFlags &= ~ID_MEAS_USED_OBJ;
     205    if (measureBig) { measureBig[k].dbFlags &= ~ID_MEAS_USED_OBJ; }
     206
     207    // does the measurement pass the supplied filtering constraints?
     208    // MeasFilterTestTiny does not test psfQF
     209    // exclude bad detections based on: photcodes, psfQF, time range, photflags & astromBadMask, mag_inst
     210    int keepMeasure = measureBig ? MeasFilterTest(&measureBig[k], FALSE) : MeasFilterTestTiny(&measure[k], FALSE);
     211    if (!keepMeasure) {
     212      continue;
     213    }
     214
     215    double Ri = getMeanR (&measure[k], average, secfilt);
     216    double Di = getMeanD (&measure[k], average, secfilt);
     217
     218    // mark (as POOR) any measurements which are deviant from the mean by > ExcludeBogusRadius
     219    if (ExcludeBogus) {
     220      coords.crval1 = average[0].R;
     221      coords.crval2 = average[0].D;
     222      double Xi, Yi;
     223      RD_to_XY (&Xi, &Yi, Ri, Di, &coords);
     224      double radius = hypot(Xi, Yi);
     225      if (radius > ExcludeBogusRadius) {
     226        measure[k].dbFlags |= ID_MEAS_POOR_ASTROM;
     227        if (measureBig) { measureBig[k].dbFlags |= ID_MEAS_POOR_ASTROM; }
    132228        continue;
    133229      }
    134 
    135       NcBlue = 0;
    136       NcRed = 0;
    137       N = 0;
    138       m = catalog[i].average[j].measureOffset;
    139       MeasureTiny *measure = &catalog[i].measureT[m];
    140       Measure *measureBig = catalog[i].measure ? &catalog[i].measure[m] : NULL;
    141       // when we update the output measure values, we need to do it here
    142 
    143       mode = FIT_MODE;
    144 
    145       // XVERB |= (catalog[i].averge[j].objID == 0xc90) && (catalog[i].average[j].catID == 0x2a1e);
    146       XVERB |= (catalog[i].average[j].objID == OBJ_ID_SRC) && (catalog[i].average[j].catID == CAT_ID_SRC);
    147       XVERB |= (catalog[i].average[j].objID == OBJ_ID_DST) && (catalog[i].average[j].catID == CAT_ID_DST);
    148 
    149       // find the basic properties of the detections for this object (Tmin, Tmax, Tmean)
    150       for (k = 0; k < catalog[i].average[j].Nmeasure; k++) {
    151 
    152         if (XVERB) {
    153           char *date = ohana_sec_to_date (measure[k].t);
    154           int dbFlagsBig = measureBig ? measureBig[k].dbFlags : 0;
    155           fprintf (stderr, OFF_T_FMT" %f %f %s : 0x%08x : 0x%08x\n",  k, measure[k].R, measure[k].D, date, measure[k].dbFlags, dbFlagsBig);
    156           free (date);
    157         }
    158 
    159         // reset the bit to note that a detection was used (or not)
    160         measure[k].dbFlags &= ~ID_MEAS_USED_OBJ;
    161         if (measureBig) { measureBig[k].dbFlags &= ~ID_MEAS_USED_OBJ; }
    162 
    163         // does the measurement pass the supplied filtering constraints?
    164         // MeasFilterTestTiny does not test psfQF
    165         // exclude bad detections based on: photcodes, psfQF, time range, photflags & astromBadMask, mag_inst
    166         int keepMeasure = measureBig ? MeasFilterTest(&measureBig[k], FALSE) : MeasFilterTestTiny(&measure[k], FALSE);
    167         if (!keepMeasure) {
    168           continue;
    169         }
    170 
    171         // mark (as POOR) any measurements which are deviant from the mean by > ExcludeBogusRadius
    172         if (ExcludeBogus) {
    173           double Ri = getMeanR (&measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    174           double Di = getMeanD (&measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    175           coords.crval1 = catalog[i].average[j].R;
    176           coords.crval2 = catalog[i].average[j].D;
    177           double Xi, Yi;
    178           RD_to_XY (&Xi, &Yi, Ri, Di, &coords);
    179           double radius = hypot(Xi, Yi);
    180           if (radius > ExcludeBogusRadius) {
    181               measure[k].dbFlags |= ID_MEAS_POOR_ASTROM;
    182               if (measureBig) { measureBig[k].dbFlags |= ID_MEAS_POOR_ASTROM; }
    183               continue;
    184           }
    185           measure[k].dbFlags &= ~ID_MEAS_POOR_ASTROM;
    186           if (measureBig) { measureBig[k].dbFlags &= ~ID_MEAS_POOR_ASTROM; }
    187         }
    188 
    189         // outlier rejection
    190         if (FALSE && FlagOutlier && (measure[k].dbFlags & ID_MEAS_POOR_ASTROM)) {
    191           continue;
    192         }
    193 
    194         R[N] = getMeanR (&measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    195         D[N] = getMeanD (&measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    196 
    197         // XXX I think this is a problem: T[] is time in years relative to J2000, but ParFactor expects
    198         // to get Time in years relative to UNIX Tzero (1970/01/01)
    199         T[N] = (measure[k].t - T2000) / (86400*365.25) ; // time relative to J2000 in years
    200 
    201         // dX, dY : error in arcsec --
    202         dX[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_RA);
    203         dY[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_DEC);
    204 
    205         // allow a given photcode or measurement to be
    206         // ignored if the error is NAN (for photcode, set astromErrSys to NaN)
    207         if (isnan(dX[N])) continue;
    208         if (isnan(dY[N])) continue;
    209 
    210         // add systematic error in quadrature, if desired
    211         // only do this after the fit has converged (or you will never improve the poor images)
    212         // if (INCLUDE_SYS_ERR) {
    213         // float dRsys = FromShortPixels(measure[k].dRsys);
    214         // dX[N] = hypot(dX[N], dRsys);
    215         // dY[N] = hypot(dY[N], dRsys);
    216         // }
    217 
    218         // dX[N] = 0.1;
    219         // dY[N] = 0.1;
    220 
    221         dT[N] = measure[k].dt;
    222 
    223         // XXX this is (slightly) inconsistent: dX,dY are the X and Y direction errors in
    224         // arcseconds.  dR, dD are the errors in those directions in degrees.  IF we have
    225         // non-circular errors (different values for X and Y), then dR and dD will be
    226         // incorrect: they would need to be rotated to take out the position angle
    227         dR[N] = dX[N] / 3600.0;
    228         dD[N] = dY[N] / 3600.0;
    229 
    230         if (setRefColor) {
    231           float colorBlue = getColorBlue (m+k, i);
    232           if (!isnan(colorBlue)) {
    233             C_blue[NcBlue] = colorBlue;
    234             NcBlue++;
    235           }
    236           float colorRed = getColorRed (m+k, i);
    237           if (!isnan(colorRed)) {
    238             C_red[NcRed] = colorRed;
    239             NcRed++;
    240           }
    241         }
    242 
    243         measure[k].dbFlags |= ID_MEAS_USED_OBJ;
    244         if (measureBig) { measureBig[k].dbFlags |= ID_MEAS_USED_OBJ; }
    245 
    246         N++;
    247       } // loop over measurements : catalog[i].average[j].Nmeasure
    248 
    249       // if we have too few good detections for the desired fit, or too limited a
    250       // baseline, use a fit with fewer parameters.  XXX if we have too few measurements
    251       // for even the average position, consider including the lower-quality detections?
    252 
    253       // find Tmin & Tmax from the list of accepted measurements
    254       Tmean = 0;
    255       Tmin = Tmax = T[0];
    256       for (k = 0; k < N; k++) {
    257         Tmin = MIN(Tmin, T[k]);
    258         Tmax = MAX(Tmax, T[k]);
    259         Tmean += T[k];
     230      measure[k].dbFlags &= ~ID_MEAS_POOR_ASTROM;
     231      if (measureBig) { measureBig[k].dbFlags &= ~ID_MEAS_POOR_ASTROM; }
     232    }
     233
     234    // outlier rejection
     235    if (FALSE && FlagOutlier && (measure[k].dbFlags & ID_MEAS_POOR_ASTROM)) {
     236      continue;
     237    }
     238
     239    R[N] = Ri;
     240    D[N] = Di;
     241
     242    // measure[k].t is UNIX seconds, T2000 is UNIX seconds for J2000.
     243    // T[] is time in years since J2000 (jd = 2451545)
     244    T[N] = (measure[k].t - T2000) / (86400*365.25) ; // time relative to J2000 in years
     245
     246    // dX, dY : error in arcsec --
     247    dX[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_RA);
     248    dY[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_DEC);
     249
     250    // allow a given photcode or measurement to be
     251    // ignored if the error is NAN (for photcode, set astromErrSys to NaN)
     252    if (isnan(dX[N])) continue;
     253    if (isnan(dY[N])) continue;
     254
     255    // add systematic error in quadrature, if desired
     256    // only do this after the fit has converged (or you will never improve the poor images)
     257    // if (INCLUDE_SYS_ERR) {
     258    // float dRsys = FromShortPixels(measure[k].dRsys);
     259    // dX[N] = hypot(dX[N], dRsys);
     260    // dY[N] = hypot(dY[N], dRsys);
     261    // }
     262
     263    // dX[N] = 0.1;
     264    // dY[N] = 0.1;
     265
     266    dT[N] = measure[k].dt;
     267
     268    // XXX this is (slightly) inconsistent: dX,dY are the X and Y direction errors in
     269    // arcseconds.  dR, dD are the errors in those directions in degrees.  IF we have
     270    // non-circular errors (different values for X and Y), then dR and dD will be
     271    // incorrect: they would need to be rotated to take out the position angle
     272    dR[N] = dX[N] / 3600.0;
     273    dD[N] = dY[N] / 3600.0;
     274
     275    if (setRefColor) {
     276      float colorBlue = getColorBlue (m+k, i);
     277      if (!isnan(colorBlue)) {
     278        C_blue[NcBlue] = colorBlue;
     279        NcBlue++;
    260280      }
    261       // XXX add the parallax factor range as a criterion as well
    262       Trange = Tmax - Tmin;
    263       if (Trange < PM_DT_MIN) mode = FIT_AVERAGE;
    264       if (((mode == FIT_PM_ONLY) || (mode == FIT_PM_AND_PAR)) && (N <= PM_TOOFEW)) mode = FIT_AVERAGE;
    265 
    266       if (RELASTRO_OP == OP_HIGH_SPEED) {
    267           Tmean = 0.5*(Tmax - Tmin);
    268       } else {
    269           Tmean /= (float) N;
     281      float colorRed = getColorRed (m+k, i);
     282      if (!isnan(colorRed)) {
     283        C_red[NcRed] = colorRed;
     284        NcRed++;
    270285      }
    271 
    272       // too few measurements for average position (require 2 values)
    273       if (N < SRC_MEAS_TOOFEW) {
    274         if (N < 2) continue;
     286    }
     287
     288    measure[k].dbFlags |= ID_MEAS_USED_OBJ;
     289    if (measureBig) { measureBig[k].dbFlags |= ID_MEAS_USED_OBJ; }
     290
     291    N++;
     292  } // loop over measurements : average[0].Nmeasure
     293
     294  if (N < 1) {
     295    if (isfinite(average[0].Rstk) && isfinite(average[0].Dstk)) {
     296      average[0].R  = average[0].Rstk;
     297      average[0].D  = average[0].Dstk;
     298      average[0].dR = average[0].dRstk;
     299      average[0].dD = average[0].dDstk;
     300    }
     301    return FALSE;
     302  }
     303
     304  // if we have too few good detections for the desired fit, or too limited a
     305  // baseline, use a fit with fewer parameters.  XXX if we have too few measurements
     306  // for even the average position, consider including the lower-quality detections?
     307
     308  // find Tmin & Tmax from the list of accepted measurements
     309  double Tmean = 0.0;
     310  double Tmin = T[0];
     311  double Tmax = T[0];
     312  for (k = 0; k < N; k++) {
     313    Tmin = MIN(Tmin, T[k]);
     314    Tmax = MAX(Tmax, T[k]);
     315    Tmean += T[k];
     316  }
     317  double Trange = Tmax - Tmin;
     318
     319  if (RELASTRO_OP == OP_HIGH_SPEED) {
     320    Tmean = 0.5*(Tmax - Tmin);
     321  } else {
     322    Tmean /= (float) N;
     323  }
     324
     325  /* we need to do the fit in a locally linear space; choose a ref coordinate */
     326  coords.crval1 = R[0];
     327  coords.crval2 = D[0];
     328
     329  // to judge the quality of the PM and PAR fits, we need to fit all three models and compare Chisq
     330
     331  // *** first fit for the proper motion (skip fit if Trange or Npts is too small) ***
     332  if ((mode == FIT_PM_ONLY) || (mode == FIT_PM_AND_PAR)) {
     333    if (Trange < PM_DT_MIN) {
     334      mode = FIT_AVERAGE;
     335      goto skipPM;
     336    }
     337    if (N <= PM_TOOFEW) {
     338      mode = FIT_AVERAGE;
     339      goto skipPM;
     340    }
     341
     342    // project all of the R,D coordinates to a plane centered on this coordinate. set
     343    // the times to be relative to Tmean (this is required for parallax as well)
     344    for (k = 0; k < N; k++) {
     345      RD_to_XY (&X[k], &Y[k], R[k], D[k], &coords);
     346      T[k] -= Tmean;
     347      if (XVERB) {
     348        fprintf (stderr, OFF_T_FMT" %f %f %f  %f %f +/- %f %f\n",  k, T[k], R[k], D[k], X[k], Y[k], dX[k], dY[k]);
    275349      }
    276 
    277       /* we need to do the fit in a locally linear space; choose a ref coordinate */
    278       coords.crval1 = R[0];
    279       coords.crval2 = D[0];
    280 
    281       // to judge the quality of the PM and PAR fits, we need to fit all three models and compare Chisq
    282 
    283       if ((mode == FIT_PM_ONLY) || (mode == FIT_PM_AND_PAR)) {
    284         // project all of the R,D coordinates to a plane centered on this coordinate. set
    285         // the times to be relative to Tmean (this is required for parallax as well)
    286         for (k = 0; k < N; k++) {
    287           RD_to_XY (&X[k], &Y[k], R[k], D[k], &coords);
    288           T[k] -= Tmean;
    289           if (XVERB) {
    290             fprintf (stderr, OFF_T_FMT" %f %f %f  %f %f +/- %f %f\n",  k, T[k], R[k], D[k], X[k], Y[k], dX[k], dY[k]);
    291           }
    292         }         
    293 
    294         FitPM (&fitPM, X, dX, Y, dY, T, N, XVERB);
    295 
    296         if (XVERB) fprintf (stderr, "fitted PM:  %f - %f : %f %f : %f %f : %f vs %f\n", Tmin, Tmax, fitPM.Ro, fitPM.Do, fitPM.uR, fitPM.uD, fitPM.chisq, fitAve.chisq);
    297 
    298         // project Ro, Do back to RA,DEC
    299         XY_to_RD (&fitPM.Ro, &fitPM.Do, fitPM.Ro, fitPM.Do, &coords);
    300         if (XVERB) fprintf (stderr, "project: %f %f : %f %f : %f\n", fitPM.Ro, fitPM.Do, fitPM.uR, fitPM.uD, fitPM.p);
    301 
    302         fitPM.p  = fitPM.dp  = 0.0;
    303         catalog[i].average[j].flags |= ID_STAR_FIT_PM;
    304         Npm ++;
    305 
    306         // XXX a hard-wired hack...
    307         if ((fabs(fitPM.uR) > 2.0) || (fabs(fitPM.uD) > 2.0)) {
    308           mode = FIT_AVERAGE;
    309           catalog[i].average[j].flags |= ID_STAR_BAD_PM;
    310         }
    311       }
    312 
    313       if (mode == FIT_PM_AND_PAR) {
    314         float pXmin = +2.0;
    315         float pXmax = -2.0;
    316         float pYmin = +2.0;
    317         float pYmax = -2.0;
    318         for (k = 0; k < N; k++) {
    319           ParFactor (&pX[k], &pY[k], R[k], D[k], T[k], Tmean);
    320           pXmin = MIN (pXmin, pX[k]);
    321           pXmax = MAX (pXmax, pX[k]);
    322           pYmin = MIN (pYmin, pY[k]);
    323           pYmax = MAX (pYmax, pY[k]);
    324         }
    325         float dXRange = pXmax - pXmin;
    326         float dYRange = pYmax - pYmin;
    327         float parRange = hypot (dXRange, dYRange);
     350    }     
     351
     352    FitPM (&fitPM, X, dX, Y, dY, T, N, XVERB);
     353
     354    if (XVERB) fprintf (stderr, "fitted PM:  %f - %f : %f %f : %f %f : %f vs %f\n", Tmin, Tmax, fitPM.Ro, fitPM.Do, fitPM.uR, fitPM.uD, fitPM.chisq, fitAve.chisq);
     355
     356    // project Ro, Do back to RA,DEC
     357    XY_to_RD (&fitPM.Ro, &fitPM.Do, fitPM.Ro, fitPM.Do, &coords);
     358    if (XVERB) fprintf (stderr, "project: %f %f : %f %f : %f\n", fitPM.Ro, fitPM.Do, fitPM.uR, fitPM.uD, fitPM.p);
     359
     360    fitPM.p  = fitPM.dp  = 0.0;
     361    average[0].flags |= ID_STAR_FIT_PM;
     362    fitStats->Npm ++;
     363
     364    // XXX a hard-wired hack...
     365    if ((fabs(fitPM.uR) > 2.0) || (fabs(fitPM.uD) > 2.0)) {
     366      mode = FIT_AVERAGE;
     367      average[0].flags |= ID_STAR_BAD_PM;
     368    }
     369  }
     370 
     371skipPM:
     372  // fit the parallax + proper-motion model
     373  // NOTE : we only fit PAR if we have already fitted for proper motion. if we do not fit PM or we fail
     374  // to fit PM, we do not attempt PAR.  thus failure to fit PAR falls back to PM-only
     375  if (mode == FIT_PM_AND_PAR) {
     376    if (Trange < PM_DT_MIN) {
     377      mode = FIT_PM_ONLY;
     378      goto skipPAR;
     379    }
     380    if (N <= PAR_TOOFEW) {
     381      mode = FIT_PM_ONLY;
     382      goto skipPAR;
     383    }
     384    float pXmin = +2.0;
     385    float pXmax = -2.0;
     386    float pYmin = +2.0;
     387    float pYmax = -2.0;
     388    for (k = 0; k < N; k++) {
     389      ParFactor (&pX[k], &pY[k], R[k], D[k], T[k], Tmean);
     390      pXmin = MIN (pXmin, pX[k]);
     391      pXmax = MAX (pXmax, pX[k]);
     392      pYmin = MIN (pYmin, pY[k]);
     393      pYmax = MAX (pYmax, pY[k]);
     394    }
     395    float dXRange = pXmax - pXmin;
     396    float dYRange = pYmax - pYmin;
     397    float parRange = hypot (dXRange, dYRange);
    328398       
    329 # define PAR_TOOFEW 5
    330         if ((parRange >= PAR_FACTOR_MIN) && (N > PAR_TOOFEW)) {
    331           FitPMandPar (&fitPAR, X, dX, Y, dY, T, pX, pY, N, XVERB);
    332           if (XVERB) fprintf (stderr, "fitted PM+PAR:  %f - %f : %f %f : %f %f : %f %f : %f vs %f vs %f\n", Tmin, Tmax, fitPAR.Ro, fitPAR.Do, fitPAR.uR, fitPAR.uD, fitPAR.p, fitPAR.dp, fitPAR.chisq, fitPM.chisq, fitAve.chisq);
    333 
    334           XY_to_RD (&fitPAR.Ro, &fitPAR.Do, fitPAR.Ro, fitPAR.Do, &coords);
    335           catalog[i].average[j].flags |= ID_STAR_FIT_PAR;
    336           Npar ++;
    337 
    338           // XXX a hard-wired hack...
    339           if ((fabs(fitPAR.uR) > 2.0) || (fabs(fitPAR.uD) > 2.0)) {
    340             mode = FIT_AVERAGE;
    341             catalog[i].average[j].flags |= ID_STAR_BAD_PM;
    342           }
    343         } else {
    344           // need to set mode = FIT_PM_ONLY if we do not fit for parallax
    345           mode = FIT_PM_ONLY;
    346         }
    347       }   
    348 
    349       // fit the average model
    350       if ((mode == FIT_AVERAGE) || (mode == FIT_PM_ONLY) || (mode == FIT_PM_AND_PAR)) {
    351         liststats_pos (R, dR, N, &statsR, XVERB); // WARNING: this function modifies R (do not use after here)
    352         liststats_pos (D, dD, N, &statsD, XVERB); // WARNING: this function modifies D (do not use after here)
    353 
    354         fitAve.Ro = statsR.mean;
    355         fitAve.dRo = 3600.0*statsR.sigma;
    356 
    357         fitAve.Do = statsD.mean;
    358         fitAve.dDo = 3600.0*statsD.sigma;
    359 
    360         fitAve.chisq = 0.5 * (statsR.chisq + statsD.chisq);
    361         fitAve.Nfit = N;
    362 
    363         fitAve.uR = fitAve.duR = 0.0;
    364         fitAve.uD = fitAve.duD = 0.0;
    365         fitAve.p  = fitAve.dp  = 0.0;
    366         catalog[i].average[j].flags |= ID_STAR_FIT_AVE;
    367         Nave ++;
    368       }
    369 
    370       if (setRefColor) {
    371         float colorMedian;
    372         dsort (C_blue, NcBlue);
    373         colorMedian = (NcBlue > 0) ? C_blue[(int)(0.5*NcBlue)] : NAN;
    374         catalog[i].average[j].refColorBlue = colorMedian;
    375         dsort (C_red, NcRed);
    376         colorMedian = (NcRed > 0) ? C_red[(int)(0.5*NcRed)] : NAN;
    377         catalog[i].average[j].refColorRed = colorMedian;
    378       }
    379 
    380       /* choose the result based on the chisq values */
    381       // XXXX for now, just use the mode as the result:
    382       result = mode;
    383 
    384       switch (result) {
    385       case FIT_AVERAGE:
    386         catalog[i].average[j].flags |= ID_STAR_USE_AVE;
    387         fit = fitAve;
    388         break;
    389       case FIT_PM_ONLY:
    390         catalog[i].average[j].flags |= ID_STAR_USE_PM;
    391         fit = fitPM;
    392         break;
    393       case FIT_PM_AND_PAR:
    394         catalog[i].average[j].flags |= ID_STAR_USE_PAR;
    395         fit = fitPAR;
    396         break;
    397       }
    398       if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f) pm=(%f %f) plx=(%f +/- %f)\n",
    399                           catalog[i].average[j].R,
    400                           catalog[i].average[j].D,
    401                           fit.Ro, fit.Do,
    402                           3600*(catalog[i].average[j].R - fit.Ro),
    403                           3600*(catalog[i].average[j].D - fit.Do),
    404                           fit.uR, fit.uD, fit.p, fit.dp);
    405 
    406       // make sure that the fit succeeded
    407       status = TRUE;
    408       status &= finite(fit.Ro);
    409       status &= finite(fit.Do);
    410       status &= finite(fit.dRo);
    411       status &= finite(fit.dDo);
    412       status &= finite(fit.uR);
    413       status &= finite(fit.uD);
    414       status &= finite(fit.duR);
    415       status &= finite(fit.duD);
    416       status &= finite(fit.p);
    417       status &= finite(fit.dp);
    418       if (!status) {
    419         Nskip ++;
    420         continue;
    421       }
    422 
    423       // what is the offset relative to the mean fit position?
    424       coords.crval1 = catalog[i].average[j].R;
    425       coords.crval2 = catalog[i].average[j].D;
    426 
    427       double dXoff, dYoff;
    428       RD_to_XY (&dXoff, &dYoff, fit.Ro, fit.Do, &coords);
    429       float dPos = hypot (dXoff, dYoff);
    430       if (dPos > MaxMeanOffset) {
    431         if (Noffset < 100) {
    432           fprintf (stderr, "(%f,%f) -> (%f,%f) (%f,%f)\n", coords.crval1, coords.crval2, fit.Ro, fit.Do, dXoff, dYoff);
    433         }
    434         Noffset ++;
    435         continue;
    436       }
    437 
    438 
    439       // the measure fields must be updated before the average fields
    440       for (k = 0; k < catalog[i].average[j].Nmeasure; k++) {
    441         setMeanR (fit.Ro, &measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    442         setMeanD (fit.Do, &measure[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    443         if (measureBig) {
    444           setMeanR_Big (fit.Ro, &measureBig[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    445           setMeanD_Big (fit.Do, &measureBig[k], &catalog[i].average[j], &catalog[i].secfilt[j*Nsecfilt]);
    446         }
    447       }     
    448 
    449       catalog[i].average[j].R   = fit.Ro; // RA in degrees
    450       catalog[i].average[j].D   = fit.Do; // DEC in degrees
    451       catalog[i].average[j].dR  = fit.dRo; // RA scatter in arcsec
    452       catalog[i].average[j].dD  = fit.dDo; // DEC scatter in arcsec
    453 
    454       catalog[i].average[j].uR  = fit.uR; // RA proper motion in arcsec/year
    455       catalog[i].average[j].uD  = fit.uD; // DEC proper motion in arcsec/year
    456       catalog[i].average[j].duR = fit.duR; // RA proper motion error in arcsec/year
    457       catalog[i].average[j].duD = fit.duD; // DEC proper motion error in arcsec/year
    458 
    459       catalog[i].average[j].P   = fit.p; // parallax in arcsec
    460       catalog[i].average[j].dP  = fit.dp; // parallax error in arcsec
    461 
    462       catalog[i].average[j].ChiSqAve  = fitAve.chisq;
    463       catalog[i].average[j].ChiSqPM   = fitPM.chisq;
    464       catalog[i].average[j].ChiSqPar  = fitPAR.chisq;
    465       catalog[i].average[j].Tmean = (Tmean * 86400 * 365.25) + T2000;
    466       catalog[i].average[j].Trange = (Trange * 86400 * 365.25);
    467       catalog[i].average[j].Npos = fit.Nfit;
    468 
    469       // XXX EAM 20140812: for a test, set average.Rstk,Dstk, etc to match R,D
    470       catalog[i].average[j].Rstk  = fit.Ro; // RA in degrees
    471       catalog[i].average[j].Dstk  = fit.Do; // DEC in degrees
    472       catalog[i].average[j].dRstk = fit.dRo; // RA scatter in arcsec
    473       catalog[i].average[j].dDstk = fit.dDo; // DEC scatter in arcsec
    474 
    475       // unset the NO_ASTROM bit (not(NO_ASTROM) == HAVE_ASTROM)
    476       catalog[i].average[j].flags &= ~ID_STAR_NO_ASTROM;
    477 
    478       if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f) pm=(%f %f) chisq=(%f, %f, %f)\n",
    479                           catalog[i].average[j].R,
    480                           catalog[i].average[j].D,
    481                           fit.Ro, fit.Do,
    482                           3600*(catalog[i].average[j].R - fit.Ro),
    483                           3600*(catalog[i].average[j].D - fit.Do),
    484                           catalog[i].average[j].uR,
    485                           catalog[i].average[j].uD,
    486                           fitAve.chisq, fitPM.chisq, fitPAR.chisq);
    487     }
    488 
    489     NaveSum += Nave;
    490     NpmSum += Npm;
    491     NparSum += Npar;
    492     NskipSum += Nskip;
    493     NoffSum += Noffset;
    494     if (VERBOSE) fprintf (stderr, "catalog %d : "OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par : Nskip "OFF_T_FMT", Noffset "OFF_T_FMT"\n",  i,  Nave,  Npm,  Npar,  Nskip, Noffset);
    495   }
    496 
    497   freeObjectData ();
    498 
    499   if (VERBOSE) fprintf (stderr, "fitted "OFF_T_FMT" objects ("OFF_T_FMT" ave, "OFF_T_FMT" pm, "OFF_T_FMT" par), skipped "OFF_T_FMT", "OFF_T_FMT" have too large an offset\n",  (NaveSum + NpmSum + NparSum),  NaveSum,  NpmSum,  NparSum,  NskipSum, NoffSum);
     399    if (parRange < PAR_FACTOR_MIN) {
     400      mode = FIT_PM_ONLY;
     401      goto skipPAR;
     402    }
     403
     404    FitPMandPar (&fitPAR, X, dX, Y, dY, T, pX, pY, N, XVERB);
     405    if (XVERB) fprintf (stderr, "fitted PM+PAR:  %f - %f : %f %f : %f %f : %f %f : %f vs %f vs %f\n", Tmin, Tmax, fitPAR.Ro, fitPAR.Do, fitPAR.uR, fitPAR.uD, fitPAR.p, fitPAR.dp, fitPAR.chisq, fitPM.chisq, fitAve.chisq);
     406
     407    XY_to_RD (&fitPAR.Ro, &fitPAR.Do, fitPAR.Ro, fitPAR.Do, &coords);
     408    average[0].flags |= ID_STAR_FIT_PAR;
     409    fitStats->Npar ++;
     410
     411    // XXX a hard-wired hack...
     412    if ((fabs(fitPAR.uR) > 2.0) || (fabs(fitPAR.uD) > 2.0)) {
     413      mode = FIT_PM_ONLY;
     414    }
     415  }       
     416
     417skipPAR:
     418  {
     419    // ALWAYS fit the average model
     420    StatType statsR, statsD;
     421    liststats_pos (R, dR, N, &statsR, XVERB); // WARNING: this function modifies R (do not use after here)
     422    liststats_pos (D, dD, N, &statsD, XVERB); // WARNING: this function modifies D (do not use after here)
     423
     424    fitAve.Ro = statsR.mean;
     425    fitAve.dRo = 3600.0*statsR.sigma;
     426
     427    fitAve.Do = statsD.mean;
     428    fitAve.dDo = 3600.0*statsD.sigma;
     429
     430    fitAve.chisq = (N > 1) ? 0.5 * (statsR.chisq + statsD.chisq) : NAN;
     431    fitAve.Nfit = N;
     432
     433    fitAve.uR = fitAve.duR = 0.0;
     434    fitAve.uD = fitAve.duD = 0.0;
     435    fitAve.p  = fitAve.dp  = 0.0;
     436    average[0].flags |= ID_STAR_FIT_AVE;
     437    fitStats->Nave ++;
     438  }
     439
     440  if (setRefColor) {
     441    float colorMedian;
     442    dsort (C_blue, NcBlue);
     443    colorMedian = (NcBlue > 0) ? C_blue[(int)(0.5*NcBlue)] : NAN;
     444    average[0].refColorBlue = colorMedian;
     445    dsort (C_red, NcRed);
     446    colorMedian = (NcRed > 0) ? C_red[(int)(0.5*NcRed)] : NAN;
     447    average[0].refColorRed = colorMedian;
     448  }
     449
     450  /* choose the result based on the chisq values */
     451  // XXXX for now, just use the mode as the result:
     452  int result = mode;
     453
     454  switch (result) {
     455    case FIT_AVERAGE:
     456      average[0].flags |= ID_STAR_USE_AVE;
     457      fit = fitAve;
     458      break;
     459    case FIT_PM_ONLY:
     460      average[0].flags |= ID_STAR_USE_PM;
     461      fit = fitPM;
     462      break;
     463    case FIT_PM_AND_PAR:
     464      average[0].flags |= ID_STAR_USE_PAR;
     465      fit = fitPAR;
     466      break;
     467  }
     468  if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f) pm=(%f %f) plx=(%f +/- %f)\n",
     469                      average[0].R,
     470                      average[0].D,
     471                      fit.Ro, fit.Do,
     472                      3600*(average[0].R - fit.Ro),
     473                      3600*(average[0].D - fit.Do),
     474                      fit.uR, fit.uD, fit.p, fit.dp);
     475
     476  // make sure that the fit succeeded
     477  int status = TRUE;
     478  status &= finite(fit.Ro);
     479  status &= finite(fit.Do);
     480  status &= finite(fit.dRo);
     481  status &= finite(fit.dDo);
     482  status &= finite(fit.uR);
     483  status &= finite(fit.uD);
     484  status &= finite(fit.duR);
     485  status &= finite(fit.duD);
     486  status &= finite(fit.p);
     487  status &= finite(fit.dp);
     488  if (!status) {
     489    fitStats->Nskip ++;
     490    return FALSE; // XXX ??
     491  }
     492
     493  // what is the offset relative to the mean fit position?
     494  coords.crval1 = average[0].R;
     495  coords.crval2 = average[0].D;
     496
     497  double dXoff, dYoff;
     498  RD_to_XY (&dXoff, &dYoff, fit.Ro, fit.Do, &coords);
     499  float dPos = hypot (dXoff, dYoff);
     500  if (dPos > MaxMeanOffset) {
     501    if (fitStats->Noffset < 100) {
     502      fprintf (stderr, "(%f,%f) -> (%f,%f) (%f,%f)\n", coords.crval1, coords.crval2, fit.Ro, fit.Do, dXoff, dYoff);
     503    }
     504    fitStats->Noffset ++;
     505    return FALSE; // XXX ??
     506  }
     507
     508  average[0].R          = fit.Ro; // RA in degrees
     509  average[0].D          = fit.Do; // DEC in degrees
     510  average[0].dR         = fit.dRo; // RA scatter in arcsec
     511  average[0].dD         = fit.dDo; // DEC scatter in arcsec
     512
     513  average[0].uR         = fit.uR; // RA proper motion in arcsec/year
     514  average[0].uD         = fit.uD; // DEC proper motion in arcsec/year
     515  average[0].duR        = fit.duR; // RA proper motion error in arcsec/year
     516  average[0].duD        = fit.duD; // DEC proper motion error in arcsec/year
     517
     518  average[0].P          = fit.p; // parallax in arcsec
     519  average[0].dP         = fit.dp; // parallax error in arcsec
     520
     521  average[0].ChiSqAve   = fitAve.chisq;
     522  average[0].ChiSqPM    = fitPM.chisq;
     523  average[0].ChiSqPar   = fitPAR.chisq;
     524
     525  average[0].Tmean      = (Tmean * 86400 * 365.25) + T2000;
     526  average[0].Trange     = (Trange * 86400 * 365.25);
     527  average[0].Npos       = fit.Nfit;
     528
     529  // unset the NO_ASTROM bit (not(NO_ASTROM) == HAVE_ASTROM)
     530  average[0].flags &= ~ID_STAR_NO_ASTROM;
     531
     532  if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f) pm=(%f %f) chisq=(%f, %f, %f)\n",
     533                      average[0].R,
     534                      average[0].D,
     535                      fit.Ro, fit.Do,
     536                      3600*(average[0].R - fit.Ro),
     537                      3600*(average[0].D - fit.Do),
     538                      average[0].uR,
     539                      average[0].uD,
     540                      fitAve.chisq, fitPM.chisq, fitPAR.chisq);
     541
    500542  return (TRUE);
    501543}
     544
     545// This function operates on both Measure and MeasureTiny.  In the big stages, this should
     546// be called with just MeasureTiny set and Measure == NULL
     547int UpdateObjects_Stack (Average *average, SecFilt *secfilt, MeasureTiny *measure, Measure *measureBig, int Nsecfilt, FitStats *fitStats) {
     548
     549  off_t k;
     550
     551  // set the default values
     552  average[0].Rstk  = NAN; // RA in degrees
     553  average[0].Dstk  = NAN; // DEC in degrees
     554  average[0].dRstk = NAN; // RA scatter in arcsec
     555  average[0].dDstk = NAN; // DEC scatter in arcsec
     556
     557  /* calculate the average value of R,D for a single star */
     558  PMFit fitAve;
     559  memset (&fitAve, 0, sizeof(fitAve));
     560  fitAve.chisq = NAN;
     561
     562  if (average[0].Nmeasure == 0) return TRUE;
     563
     564  int N = 0;
     565
     566  int XVERB = FALSE;
     567  XVERB |= (average[0].objID == OBJ_ID_SRC) && (average[0].catID == CAT_ID_SRC);
     568  XVERB |= (average[0].objID == OBJ_ID_DST) && (average[0].catID == CAT_ID_DST);
     569
     570  // find the basic properties of the detections for this object (Tmin, Tmax, Tmean)
     571  for (k = 0; k < average[0].Nmeasure; k++) {
     572
     573    if (XVERB) {
     574      char *date = ohana_sec_to_date (measure[k].t);
     575      int dbFlagsBig = measureBig ? measureBig[k].dbFlags : 0;
     576      fprintf (stderr, "stack: "OFF_T_FMT" %f %f %s : 0x%08x : 0x%08x\n",  k, measure[k].R, measure[k].D, date, measure[k].dbFlags, dbFlagsBig);
     577      free (date);
     578    }
     579
     580    // SKIP everything except gpc1 stack data
     581    if (!isGPC1stack(measure[k].photcode)) continue;
     582
     583    // exclude bad detections based on: photcodes, psfQF, time range, photflags & astromBadMask, mag_inst
     584    int keepMeasure = measureBig ? MeasFilterTest(&measureBig[k], FALSE) : MeasFilterTestTiny(&measure[k], FALSE);
     585    if (!keepMeasure) {
     586      continue;
     587    }
     588
     589    R[N] = getMeanR (&measure[k], average, secfilt);
     590    D[N] = getMeanD (&measure[k], average, secfilt);
     591
     592    // dX, dY : error in arcsec --
     593    dX[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_RA);
     594    dY[N] = GetAstromErrorTiny (&measure[k], ERROR_MODE_DEC);
     595
     596    // allow a given photcode or measurement to be
     597    // ignored if the error is NAN (for photcode, set astromErrSys to NaN)
     598    if (isnan(dX[N])) continue;
     599    if (isnan(dY[N])) continue;
     600
     601    // XXX this is (slightly) inconsistent: dX,dY are the X and Y direction errors in
     602    // arcseconds.  dR, dD are the errors in those directions in degrees.  IF we have
     603    // non-circular errors (different values for X and Y), then dR and dD will be
     604    // incorrect: they would need to be rotated to take out the position angle
     605    dR[N] = dX[N] / 3600.0;
     606    dD[N] = dY[N] / 3600.0;
     607
     608    // XXX use a different flag for stack measurements?
     609    // measure[k].dbFlags |= ID_MEAS_USED_OBJ;
     610    // if (measureBig) { measureBig[k].dbFlags |= ID_MEAS_USED_OBJ; }
     611
     612    N++;
     613  } // loop over measurements : average[0].Nmeasure
     614
     615  // if we have too few good detections for the desired fit, or too limited a
     616  // baseline, use a fit with fewer parameters.  XXX if we have too few measurements
     617  // for even the average position, consider including the lower-quality detections?
     618
     619  // too few measurements for average position (require 2 values)
     620  if (N < 1) return FALSE; // XXX ??
     621
     622  // find the mean position
     623  StatType statsR, statsD;
     624  liststats_pos (R, dR, N, &statsR, XVERB); // WARNING: this function modifies R (do not use after here)
     625  liststats_pos (D, dD, N, &statsD, XVERB); // WARNING: this function modifies D (do not use after here)
     626
     627  fitAve.Ro = statsR.mean;
     628  fitAve.dRo = 3600.0*statsR.sigma;
     629
     630  fitAve.Do = statsD.mean;
     631  fitAve.dDo = 3600.0*statsD.sigma;
     632
     633  fitAve.chisq = 0.5 * (statsR.chisq + statsD.chisq);
     634  fitAve.Nfit = N;
     635
     636  // XXX choose stack flag? average[0].flags |= ID_STAR_FIT_AVE;
     637  fitStats->Nave ++;
     638
     639  if (XVERB) fprintf (stderr, "%f %f -> %f %f (%f,%f)\n",
     640                      average[0].R,
     641                      average[0].D,
     642                      fitAve.Ro, fitAve.Do,
     643                      3600*(average[0].R - fitAve.Ro),
     644                      3600*(average[0].D - fitAve.Do));
     645
     646  // make sure that the fit succeeded
     647  int status = TRUE;
     648  status &= finite(fitAve.Ro);
     649  status &= finite(fitAve.Do);
     650  status &= finite(fitAve.dRo);
     651  status &= finite(fitAve.dDo);
     652  if (!status) {
     653    fitStats->Nskip ++;
     654    return FALSE;
     655  }
     656
     657  // what is the offset relative to the mean fit position?
     658  coords.crval1 = average[0].R;
     659  coords.crval2 = average[0].D;
     660
     661  double dXoff, dYoff;
     662  RD_to_XY (&dXoff, &dYoff, fitAve.Ro, fitAve.Do, &coords);
     663  float dPos = hypot (dXoff, dYoff);
     664  if (dPos > MaxMeanOffset) {
     665    if (fitStats->Noffset < 100) {
     666      fprintf (stderr, "(%f,%f) -> (%f,%f) (%f,%f)\n", coords.crval1, coords.crval2, fitAve.Ro, fitAve.Do, dXoff, dYoff);
     667    }
     668    fitStats->Noffset ++;
     669    return FALSE;
     670  }
     671
     672  // set the stack position values
     673  average[0].Rstk  = fitAve.Ro; // RA in degrees
     674  average[0].Dstk  = fitAve.Do; // DEC in degrees
     675  average[0].dRstk = fitAve.dRo; // RA scatter in arcsec
     676  average[0].dDstk = fitAve.dDo; // DEC scatter in arcsec
     677
     678  return (TRUE);
     679}
     680
     681
    502682
    503683/* fitting proper-motion and parallax:
Note: See TracChangeset for help on using the changeset viewer.