Ignore:
Timestamp:
11/19/08 20:41:16 (16 years ago)
Author:
Malte Marquarding
Message:

update from livedata CVS

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/external/atnf/PKSIO/MBFITSreader.cc

    r1427 r1452  
    2727//#                        AUSTRALIA
    2828//#
    29 //# $Id: MBFITSreader.cc,v 19.38 2008-06-26 02:24:22 cal103 Exp $
     29//# $Id: MBFITSreader.cc,v 19.54 2008-11-17 06:51:55 cal103 Exp $
    3030//#---------------------------------------------------------------------------
    3131//# The MBFITSreader class reads single dish RPFITS files (such as Parkes
     
    3535//#---------------------------------------------------------------------------
    3636
     37#include <atnf/pks/pks_maths.h>
    3738#include <atnf/PKSIO/MBFITSreader.h>
    38 #include <atnf/PKSIO/PKSMBrecord.h>
    39 
    40 #include <RPFITS.h>
     39#include <atnf/PKSIO/MBrecord.h>
    4140
    4241#include <casa/math.h>
     
    4746#include <unistd.h>
    4847
     48#include <RPFITS.h>
     49
    4950using namespace std;
    5051
     
    5253const double PI = 3.141592653589793238462643;
    5354const double TWOPI = 2.0 * PI;
     55const double HALFPI = PI / 2.0;
    5456const double R2D = 180.0 / PI;
    5557
     
    9395
    9496  cMBopen = 0;
     97
     98  // Tell RPFITSIN not to report errors directly.
     99  iostat_.errlun = -1;
     100
     101  // By default, messages are written to stderr.
     102  initMsg();
    95103}
    96104
     
    121129        int  &extraSysCal)
    122130{
     131  // Clear the message stack.
     132  clearMsg();
     133
    123134  if (cMBopen) {
    124135    close();
     
    129140  // Open the RPFITS file.
    130141  int jstat = -3;
    131   rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
    132             &cBin, &cIFno, &cSrcNo);
    133 
    134   if (jstat) {
    135     fprintf(stderr, "ERROR, failed to open MBFITS file: %s\n", rpname);
     142  if (rpfitsin(jstat)) {
     143    sprintf(cMsg, "ERROR: failed to open MBFITS file\n       %s", rpname);
     144    logMsg(cMsg);
    136145    return 1;
    137146  }
     
    149158  // Read the first header.
    150159  jstat = -1;
    151   rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
    152             &cBin, &cIFno, &cSrcNo);
    153 
    154   if (jstat) {
    155     fprintf(stderr, "ERROR, failed to read MBFITS header: %s\n", rpname);
     160  if (rpfitsin(jstat)) {
     161    sprintf(cMsg, "ERROR: failed to read MBFITS header in file\n"
     162                  "       %s", rpname);
     163    logMsg(cMsg);
    156164    close();
    157165    return 1;
     
    163171  // Non-ATNF data may not store the position in (u,v,w).
    164172  if (strncmp(names_.sta, "tid", 3) == 0) {
    165     fprintf(stderr, "WARNING, found Tidbinbilla data");
     173    sprintf(cMsg, "WARNING: Found Tidbinbilla data");
    166174    cSUpos = 1;
    167175  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
    168     fprintf(stderr, "WARNING, found Hobart data");
     176    sprintf(cMsg, "WARNING: Found Hobart data");
    169177    cSUpos = 1;
    170178  } else if (strncmp(names_.sta, "CED", 3) == 0) {
    171     fprintf(stderr, "WARNING, found Ceduna data");
     179    sprintf(cMsg, "WARNING: Found Ceduna data");
    172180    cSUpos = 1;
    173181  } else {
     
    176184
    177185  if (cSUpos) {
    178     fprintf(stderr, ", using telescope position from SU table.\n");
     186    strcat(cMsg, ", using telescope position\n         from SU table.");
     187    logMsg(cMsg);
    179188    cInterp = 0;
    180189  }
     190
     191  // Mean scan rate (for timestamp repairs).
     192  cNRate = 0;
     193  cAvRate[0] = 0.0;
     194  cAvRate[1] = 0.0;
     195  cCode5 = 0;
    181196
    182197
     
    190205
    191206  if (cNBeam <= 0) {
    192     fprintf(stderr, "ERROR, couldn't determine number of beams.\n");
     207    logMsg("ERROR, couldn't determine number of beams.");
    193208    close();
    194209    return 1;
     
    203218  // ...beams present in the data.
    204219  for (int iBeam = 0; iBeam < anten_.nant; iBeam++) {
    205     cBeams[anten_.ant_num[iBeam] - 1] = 1;
     220    // Guard against dubious beam numbers, e.g. zeroes in
     221    // 1999-09-29_1632_024848p14_071b.hpf and the four scans following.
     222    // Note that the actual beam number is decoded from the 'baseline' random
     223    // parameter for each spectrum and is only used for beam selection.
     224    int beamNo = anten_.ant_num[iBeam];
     225    if (beamNo != iBeam+1) {
     226      char sta[8];
     227      strncpy(sta, names_.sta+(8*iBeam), 8);
     228      char *cp = sta + 7;
     229      while (*cp == ' ') *(cp--) = '\0';
     230
     231      sprintf(cMsg,
     232        "WARNING: RPFITSIN returned beam number %2d for AN table\n"
     233        "         entry %2d with name '%.8s'", beamNo, iBeam+1, sta);
     234
     235      char text[8];
     236      sprintf(text, "MB%2.2d", iBeam+1);
     237      cp = cMsg + strlen(cMsg);
     238      if (strncmp(sta, text, 8) == 0) {
     239        beamNo = iBeam + 1;
     240        sprintf(cp, "; using beam number %2d.", beamNo);
     241      } else {
     242        sprintf(cp, ".");
     243      }
     244
     245      logMsg(cMsg);
     246    }
     247
     248    if (0 < beamNo && beamNo <= cNBeam) {
     249      cBeams[beamNo-1] = 1;
     250    }
    206251  }
    207252
     
    292337  // Read the first syscal record.
    293338  if (rpget(1, cEOS)) {
    294     fprintf(stderr, "ERROR, failed to read first syscal record.\n");
     339    logMsg("ERROR, failed to read first syscal record.");
    295340    close();
    296341    return 1;
     
    328373{
    329374  if (!cMBopen) {
    330     fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
     375    logMsg("ERROR, an MBFITS file has not been opened.");
    331376    return 1;
    332377  }
     
    348393    antPos[1] =  2816759.046;
    349394    antPos[2] = -3454035.950;
     395
    350396  } else if (strncmp(names_.sta, "HOH", 3) == 0) {
    351397    // Parkes HOH receiver.
     
    354400    antPos[1] =  2816759.046;
    355401    antPos[2] = -3454035.950;
     402
    356403  } else if (strncmp(names_.sta, "CA0", 3) == 0) {
    357404    // An ATCA antenna, use the array centre position.
     
    360407    antPos[1] =  2792906.182;
    361408    antPos[2] = -3200483.747;
     409
     410    // ATCA-104.  Updated position at epoch 2007/06/24 from Chris Phillips.
     411    // antPos[0] = -4751640.182; // ± 0.008
     412    // antPos[1] =  2791700.322; // ± 0.006
     413    // antPos[2] = -3200490.668; // ± 0.007
     414    //
    362415  } else if (strncmp(names_.sta, "MOP", 3) == 0) {
    363     // Mopra.
     416    // Mopra.  Updated position at epoch 2007/06/24 from Chris Phillips.
    364417    sprintf(telescope, "%-16.16s", "ATMOPRA");
    365     antPos[0] = -4682768.630;
    366     antPos[1] =  2802619.060;
    367     antPos[2] = -3291759.900;
     418    antPos[0] = -4682769.444; // ± 0.009
     419    antPos[1] =  2802618.963; // ± 0.006
     420    antPos[2] = -3291758.864; // ± 0.008
     421
    368422  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
    369423    // Hobart.
     
    372426    antPos[1] =  2522347.567;
    373427    antPos[2] = -4311562.569;
     428
    374429  } else if (strncmp(names_.sta, "CED", 3) == 0) {
    375     // Ceduna.
     430    // Ceduna.  Updated position at epoch 2007/06/24 from Chris Phillips.
    376431    sprintf(telescope, "%-16.16s", "CEDUNA");
    377     antPos[0] = -3749943.657;
    378     antPos[1] =  3909017.709;
    379     antPos[2] = -3367518.309;
     432    antPos[0] = -3753443.168; // ± 0.017
     433    antPos[1] =  3912709.794; // ± 0.017
     434    antPos[2] = -3348067.060; // ± 0.016
     435
    380436  } else if (strncmp(names_.sta, "tid", 3) == 0) {
    381437    // DSS.
     
    448504//--------------------------------------------------------- MBFITSreader::read
    449505
    450 // Read the next data record.
     506// Read the next data record (if you're feeling lucky).
    451507
    452508int MBFITSreader::read(
    453         PKSMBrecord &MBrec)
     509        MBrecord &MBrec)
    454510{
    455511  int beamNo = -1;
    456   int haveData, status;
    457   PKSMBrecord *iMBuff = 0x0;
     512  int haveData, pCode = 0, status;
     513  double raRate = 0.0, decRate = 0.0, paRate = 0.0;
     514  MBrecord *iMBuff = 0x0;
    458515
    459516  if (!cMBopen) {
    460     fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
     517    logMsg("ERROR, an MBFITS file has not been opened.");
    461518    return 1;
    462519  }
    463520
    464   // Positions recorded in the input records do not coincide with the midpoint
    465   // of the integration and hence the input must be buffered so that true
    466   // positions may be interpolated.
     521  // Positions recorded in the input records usually do not coincide with the
     522  // midpoint of the integration and hence the input must be buffered so that
     523  // true positions may be interpolated.
    467524  //
    468525  // On the first call nBeamSel buffers of length nBin, are allocated and
     
    494551
    495552      // Read the next record.
     553      pCode = 0;
    496554      if ((status = rpget(0, cEOS)) == -1) {
    497555        // EOF.
     
    502560
    503561#ifdef PKSIO_DEBUG
    504         printf("\nEnd-of-file detected, flushing last scan.\n");
     562        fprintf(stderr, "\nEnd-of-file detected, flushing last cycle.\n");
    505563#endif
    506564
     
    586644
    587645          if (cNBin > 1 && cNBeamSel > 1) {
    588             fprintf(stderr, "ERROR, cannot handle binning mode for multiple "
    589                             "beams.\n");
     646            logMsg("ERROR, cannot handle binning mode for multiple beams.");
    590647            close();
    591648            return 1;
    592649          }
    593650
    594           // Allocate buffer data storage; the PKSMBrecord constructor zeroes
     651          // Allocate buffer data storage; the MBrecord constructor zeroes
    595652          // class members such as cycleNo that are tested in the first pass
    596653          // below.
    597654          int nBuff = cNBeamSel * cNBin;
    598           cBuffer = new PKSMBrecord[nBuff];
     655          cBuffer = new MBrecord[nBuff];
    599656
    600657          // Allocate memory for spectral arrays.
     
    602659            cBuffer[ibuff].setNIFs(simulIF);
    603660            cBuffer[ibuff].allocate(0, maxChan, maxXpol);
     661
     662            // Signal that this IF in this buffer has been flushed.
     663            for (int iIF = 0; iIF < simulIF; iIF++) {
     664              cBuffer[ibuff].IFno[iIF] = 0;
     665            }
    604666          }
    605667
     
    609671          cScanNo  = 1;
    610672          cCycleNo = 0;
    611           cPrevUTC = 0.0;
     673          cPrevUTC = -1.0;
    612674        }
    613675
     
    616678          cScanNo++;
    617679          cCycleNo = 0;
    618           cPrevUTC = 0.0;
     680          cPrevUTC = -1.0;
    619681        }
    620682
    621683        // Check for change-of-day.
    622         if (cUTC < cPrevUTC - 85800.0) {
     684        double cod = 0.0;
     685        if ((cUTC + 86400.0) < (cPrevUTC + 600.0)) {
     686          // cUTC should continue to increase past 86400 during a single scan.
     687          // However, if the RPFITS file contains multiple scans that straddle
     688          // midnight then cUTC can jump backwards from the end of one scan to
     689          // the start of the next.
     690#ifdef PKSIO_DEBUG
     691          fprintf(stderr, "Change-of-day on cUTC: %.1f -> %.1f",
     692            cPrevUTC, cUTC);
     693#endif
     694          // Can't change the recorded value of cUTC directly (without also
     695          // changing dateobs) so change-of-day must be recorded separately as
     696          // an offset to be applied when comparing integration timestamps.
     697          cod = 86400.0;
     698
     699        } else if (cUTC < cPrevUTC - 1.0) {
     700          sprintf(cMsg,
     701            "WARNING: Cycle %d:%03d-%03d, UTC went backwards from\n"
     702            "         %.1f to %.1f!  Incrementing day number,\n"
     703            "         positions may be unreliable.", cScanNo, cCycleNo,
     704            cCycleNo+1, cPrevUTC, cUTC);
     705          logMsg(cMsg);
    623706          cUTC += 86400.0;
    624707        }
     
    630713
    631714        // New integration cycle?
    632         if (cUTC > cPrevUTC) {
     715        if ((cUTC+cod) > cPrevUTC) {
    633716          cCycleNo++;
    634717          cPrevUTC = cUTC + 0.0001;
     
    637720        // Apply beam selection.
    638721        beamNo = int(cBaseline / 256.0);
     722        if (beamNo == 1) {
     723          // Store the position of beam 1 for grid convergence corrections.
     724          cRA0  = cU;
     725          cDec0 = cV;
     726        }
    639727        iBeamSel = cBeamSel[beamNo-1];
    640728        if (iBeamSel < 0) continue;
     
    648736
    649737        sprintf(cDateObs, "%-10.10s", names_.datobs);
     738        cDateObs[10] = '\0';
    650739
    651740        // Compute buffer number.
     
    660749
    661750        // Begin flush cycle?
    662         if (cEOS || (iMBuff->nIF && cUTC > iMBuff->utc + 0.0001)) {
     751        if (cEOS || (iMBuff->nIF && (cUTC+cod) > (iMBuff->utc+0.0001))) {
    663752          cFlushing = 1;
    664753          cFlushBin = 0;
     
    667756
    668757#ifdef PKSIO_DEBUG
    669         printf("\n In:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, cIFno);
    670         if (cEOS) printf("Start of new scan, flushing previous scan.\n");
     758        char rel = '=';
     759        double dt = utcDiff(cUTC, cW);
     760        if (dt < 0.0) {
     761          rel = '<';
     762        } else if (dt > 0.0) {
     763          rel = '>';
     764        }
     765
     766        fprintf(stderr, "\n In:%4d%4d%3d%3d  %.3f %c %.3f (%+.3fs) - "
     767          "%sflushing\n", cScanNo, cCycleNo, beamNo, cIFno, cUTC, rel, cW, dt,
     768          cFlushing ? "" : "not ");
     769        if (cEOS) {
     770          fprintf(stderr, "Start of new scan, flushing previous scan.\n");
     771        }
    671772#endif
    672773      }
     
    733834      // as the 'u' and 'v' visibility coordinates, must be interpolated to
    734835      // the integration time which RPFITSIN returns as 'cUTC', this usually
    735       // being a second or two later.
     836      // being a second or two later.  The interpolation method used here is
     837      // based on the scan rate.
    736838      //
    737839      // "This" RA, Dec, and UTC refers to the position currently stored in
    738       // the buffer marked for output (iMBuff).  This position will be
    739       // interpolated to the midpoint of that integration using the position
    740       // recorded in the "next" integration which is currently sitting in the
    741       // RPFITS commons.  The interpolation method used here is based on the
    742       // scan rate.  At the end of a scan, or if the next position has not
    743       // been updated, the most recent determination of the scan rate will be
    744       // used for extrapolation.
     840      // the buffer marked for output (iMBuff).  This position is interpolated
     841      // to the midpoint of that integration using either
     842      //   a) the rate currently sitting in iMBuff, which was computed from
     843      //      the previous integration, otherwise
     844      //   b) from the position recorded in the "next" integration which is
     845      //      currently sitting in the RPFITS commons,
     846      // so that the position timestamps straddle the midpoint of the
     847      // integration and is thereby interpolated rather than extrapolated.
    745848      //
    746       // The rate "age" is the offset from "this" integration (in iMBuff) of
    747       // the earliest integration in the pair used to compute the rate.  A
    748       // rate "age" of 0 thus refers to the normal situation where the rate
    749       // is determined from "this" integration and the "next" one.  An age
    750       // of 1 cycle means that it is determined from "this" integration and
    751       // the one preceding it, which should be equally reliable.  An age
    752       // of 2 cycles means that the rate is determined from the previous
    753       // integration and the one before that, so the extrapolation spans one
    754       // integration cycle.  Thus it has a "staleness" of 1.
    755 
     849      // At the end of a scan, or if the next position has not been updated
     850      // or its timestamp does not advance sufficiently, the most recent
     851      // determination of the scan rate will be used for extrapolation which
     852      // is quantified by the "rate age" measured in seconds beyond the
     853      // interval defined by the position timestamps.
     854
     855      // At this point, iMBuff contains cU, cV, cW, parAngle and focusRot
     856      // stored from the previous call to rpget() for this beam (i.e. "this"),
     857      // and also raRate, decRate and paRate computed from that integration
     858      // and the previous one.
    756859      double thisRA  = iMBuff->ra;
    757860      double thisDec = iMBuff->dec;
    758861      double thisUTC = cPosUTC[iBeamSel];
     862      double thisPA  = iMBuff->parAngle + iMBuff->focusRot;
     863
     864#ifdef PKSIO_DEBUG
     865      fprintf(stderr, "This (%d) ra, dec, UTC: %9.4f %9.4f %10.3f %9.4f\n",
     866        iMBuff->cycleNo, thisRA*R2D, thisDec*R2D, thisUTC, thisPA*R2D);
     867#endif
    759868
    760869      if (cEOF || cEOS) {
    761         iMBuff->rateAge++;
    762         iMBuff->rateson = 0;
    763        
     870        // Use rates from the last cycle.
     871        raRate  = iMBuff->raRate;
     872        decRate = iMBuff->decRate;
     873        paRate  = iMBuff->paRate;
     874
    764875      } else {
    765         // Note that the time recorded as the 'w' visibility coordinate
    766         // cycles through 86400 back to 0 at midnight, whereas that in 'cUTC'
    767         // continues to increase past 86400.
    768 
    769         double nextRA  = cU;
    770         double nextDec = cV;
    771         double nextUTC = cW;
    772 
    773         if (nextUTC < thisUTC) {
    774           // Must have cycled through midnight.
    775           nextUTC += 86400.0;
    776         }
    777 
    778         // Guard against RA cycling through 24h in either direction.
    779         if (fabs(nextRA - thisRA) > PI) {
    780           if (nextRA < thisRA) {
    781             nextRA += TWOPI;
     876        if (cW == thisUTC) {
     877          // The control system at Mopra typically does not update the
     878          // positions between successive integration cycles at the end of a
     879          // scan (nor are they flagged).  In this case we use the previously
     880          // computed rates, even if from the previous scan since these are
     881          // likely to be a better guess than anything else.
     882          raRate  = iMBuff->raRate;
     883          decRate = iMBuff->decRate;
     884          paRate  = iMBuff->paRate;
     885
     886          if (cU == thisRA && cV == thisDec) {
     887            // Position and timestamp unchanged.
     888            pCode = 1;
     889
     890          } else if (fabs(cU-thisRA) < 0.0001 && fabs(cV-thisDec) < 0.0001) {
     891            // Allow small rounding errors (seen infrequently).
     892            pCode = 1;
     893
    782894          } else {
    783             nextRA -= TWOPI;
     895            // (cU,cV) are probably rubbish (not yet seen in practice).
     896            pCode = 2;
     897            cU = thisRA;
     898            cV = thisDec;
    784899          }
    785         }
    786900
    787901#ifdef PKSIO_DEBUG
    788         printf("Previous ra, dec, UTC:  %8.4f  %8.4f  %7.1f\n", thisRA*R2D,
    789           thisDec*R2D, thisUTC);
    790         printf("Current  ra, dec, UTC:  %8.4f  %8.4f  %7.1f\n", nextRA*R2D,
    791           nextDec*R2D, nextUTC);
     902          fprintf(stderr, "Next (%d) ra, dec, UTC: %9.4f %9.4f %10.3f "
     903            "(0.000s)\n", cCycleNo, cU*R2D, cV*R2D, cW);
    792904#endif
    793905
    794         // The control system at Mopra typically does not update the
    795         // positions between successive integration cycles at the end of a
    796         // scan (nor are they flagged).  In this case we use the previously
    797         // computed rates, even if from the previous scan since these are
    798         // likely to be a better guess than anything else.
    799 
    800         double dUTC = nextUTC - thisUTC;
    801 
    802         // Scan rate for this beam.
    803         if (dUTC > 0.0) {
    804           iMBuff->raRate  = (nextRA  - thisRA)  / dUTC;
    805           iMBuff->decRate = (nextDec - thisDec) / dUTC;
    806           iMBuff->rateAge = 0;
    807           iMBuff->rateson = 0;
    808 
    809           if (cInterp == 2) {
    810             // Use the same interpolation scheme as the original pksmbfits
    811             // client.  This incorrectly assumed that (nextUTC - thisUTC) is
    812             // equal to the integration time and interpolated by computing a
    813             // weighted sum of the positions before and after the required
    814             // time.
    815 
    816             double utc = iMBuff->utc;
    817             if (utc - thisUTC > 100.0) {
    818               // Must have cycled through midnight.
    819               utc -= 86400.0;
     906        } else {
     907          double nextRA  = cU;
     908          double nextDec = cV;
     909
     910          // Check and, if necessary, repair the position timestamp,
     911          // remembering that pCode refers to the NEXT cycle.
     912          pCode = fixw(cDateObs, cCycleNo, beamNo, cAvRate, thisRA, thisDec,
     913                       thisUTC, nextRA, nextDec, cW);
     914          if (pCode > 0) pCode += 3;
     915          double nextUTC = cW;
     916
     917#ifdef PKSIO_DEBUG
     918          fprintf(stderr, "Next (%d) ra, dec, UTC: %9.4f %9.4f %10.3f "
     919            "(%+.3fs)\n", cCycleNo, nextRA*R2D, nextDec*R2D, nextUTC,
     920            utcDiff(nextUTC, thisUTC));
     921#endif
     922
     923          // Compute the scan rate for this beam.
     924          double dUTC = utcDiff(nextUTC, thisUTC);
     925          if ((0.0 < dUTC) && (dUTC < 600.0)) {
     926            scanRate(cRA0, cDec0, thisRA, thisDec, nextRA, nextDec, dUTC,
     927                     raRate, decRate);
     928
     929            // Update the mean scan rate.
     930            cAvRate[0] = (cAvRate[0]*cNRate +  raRate) / (cNRate + 1);
     931            cAvRate[1] = (cAvRate[1]*cNRate + decRate) / (cNRate + 1);
     932            cNRate++;
     933
     934            // Rate of change of position angle.
     935            if (sc_.sc_ant <= anten_.nant) {
     936              paRate = 0.0;
     937            } else {
     938              int iOff = sc_.sc_q * (sc_.sc_ant - 1) - 1;
     939              double nextPA = sc_.sc_cal[iOff + 4] + sc_.sc_cal[iOff + 7];
     940              double paDiff = nextPA - thisPA;
     941              if (paDiff > PI) {
     942                paDiff -= TWOPI;
     943              } else if (paDiff < -PI) {
     944                paDiff += TWOPI;
     945              }
     946              paRate = paDiff / dUTC;
    820947            }
    821948
    822             double tw1 = 1.0 - (utc - thisUTC) / iMBuff->exposure;
    823             double tw2 = 1.0 - (nextUTC - utc) / iMBuff->exposure;
    824             double gamma = (tw2 / (tw1 + tw2)) * dUTC / (utc - thisUTC);
    825 
    826             iMBuff->raRate  *= gamma;
    827             iMBuff->decRate *= gamma;
    828           }
    829 
    830         } else {
    831           iMBuff->rateAge++;
    832 
    833           // Staleness codes.
    834           if (dUTC < 0.0) {
    835             iMBuff->rateson = 3;
     949            if (cInterp == 2) {
     950              // Use the same interpolation scheme as the original pksmbfits
     951              // client.  This incorrectly assumed that (nextUTC - thisUTC) is
     952              // equal to the integration time and interpolated by computing a
     953              // weighted sum of the positions before and after the required
     954              // time.
     955
     956              double utc = iMBuff->utc;
     957              double tw1 = 1.0 - utcDiff(utc, thisUTC) / iMBuff->exposure;
     958              double tw2 = 1.0 - utcDiff(nextUTC, utc) / iMBuff->exposure;
     959              double gamma = (tw2 / (tw1 + tw2)) * dUTC / (utc - thisUTC);
     960
     961              // Guard against RA cycling through 24h in either direction.
     962              if (fabs(nextRA - thisRA) > PI) {
     963                if (nextRA < thisRA) {
     964                  nextRA += TWOPI;
     965                } else {
     966                  nextRA -= TWOPI;
     967                }
     968              }
     969
     970              raRate  = gamma * (nextRA  - thisRA)  / dUTC;
     971              decRate = gamma * (nextDec - thisDec) / dUTC;
     972            }
     973
    836974          } else {
    837             if (nextRA != thisRA || nextDec != thisDec) {
    838               iMBuff->rateson = 2;
     975            if (cCycleNo == 2 && fabs(utcDiff(cUTC,cW)) < 600.0) {
     976              // thisUTC (i.e. cW for the first cycle) is rubbish, and
     977              // probably the position as well (extremely rare in practice,
     978              // e.g. 97-12-19_1029_235708-18_586e.hpf which actually has the
     979              // t/1000 scaling bug in the first cycle).
     980              iMBuff->pCode = 3;
     981              thisRA  = cU;
     982              thisDec = cV;
     983              thisUTC = cW;
     984              raRate  = 0.0;
     985              decRate = 0.0;
     986              paRate  = 0.0;
     987
    839988            } else {
    840               iMBuff->rateson = 1;
     989              // cW is rubbish and probably (cU,cV), and possibly the
     990              // parallactic angle and everything else as well (rarely seen
     991              // in practice, e.g. 97-12-09_0743_235707-58_327c.hpf and
     992              // 97-09-01_0034_123717-42_242b.hpf, the latter with bad
     993              // parallactic angle).
     994              pCode = 3;
     995              cU = thisRA;
     996              cV = thisDec;
     997              cW = thisUTC;
     998              raRate  = iMBuff->raRate;
     999              decRate = iMBuff->decRate;
     1000              paRate  = iMBuff->paRate;
    8411001            }
    8421002          }
     
    8441004      }
    8451005
     1006
     1007      // Choose the closest rate determination.
     1008      if (cCycleNo == 1) {
     1009        // Scan containing a single integration.
     1010        iMBuff->raRate  = 0.0;
     1011        iMBuff->decRate = 0.0;
     1012        iMBuff->paRate  = 0.0;
     1013
     1014      } else {
     1015        double dUTC = iMBuff->utc - cPosUTC[iBeamSel];
     1016
     1017        if (dUTC >= 0.0) {
     1018          // In HIPASS/ZOA, the position timestamp, which should always occur
     1019          // on the whole second, normally precedes an integration midpoint
     1020          // falling on the half-second.  Consequently, positive ages are
     1021          // always half-integral.
     1022          dUTC = utcDiff(iMBuff->utc, cW);
     1023          if (dUTC > 0.0) {
     1024            iMBuff->rateAge = dUTC;
     1025          } else {
     1026            iMBuff->rateAge = 0.0f;
     1027          }
     1028
     1029          iMBuff->raRate  =  raRate;
     1030          iMBuff->decRate = decRate;
     1031          iMBuff->paRate  =  paRate;
     1032
     1033        } else {
     1034          // In HIPASS/ZOA, negative ages occur when the integration midpoint,
     1035          // occurring on the whole second, precedes the position timestamp.
     1036          // Thus negative ages are always an integral number of seconds.
     1037          // They have only been seen to occur sporadically in the period
     1038          // 1999/05/31 to 1999/11/01, e.g. 1999-07-26_1821_005410-74_007c.hpf
     1039          //
     1040          // In recent (2008/10/07) Mopra data, small negative ages (~10ms,
     1041          // occasionally up to ~300ms) seem to be the norm, with both the
     1042          // position timestamp and integration midpoint falling close to but
     1043          // not on the integral second.
     1044          if (cCycleNo == 2) {
     1045            // We have to start with something!
     1046            iMBuff->rateAge = dUTC;
     1047
     1048          } else {
     1049            // Although we did not record the relevant position timestamp
     1050            // explicitly, it can easily be deduced.
     1051            double w = iMBuff->utc - utcDiff(cUTC, iMBuff->utc) -
     1052                       iMBuff->rateAge;
     1053            dUTC = utcDiff(iMBuff->utc, w);
     1054
     1055            if (dUTC > 0.0) {
     1056              iMBuff->rateAge = 0.0f;
     1057            } else {
     1058              iMBuff->rateAge = dUTC;
     1059            }
     1060          }
     1061
     1062          iMBuff->raRate  =  raRate;
     1063          iMBuff->decRate = decRate;
     1064          iMBuff->paRate  =  paRate;
     1065        }
     1066      }
     1067
    8461068#ifdef PKSIO_DEBUG
    847       printf("Doing position interpolation for beam %d.\n", iMBuff->beamNo);
    848       printf("RA and Dec rates and age: %7.4f  %7.4f  %d\n",
    849         iMBuff->raRate*R2D, iMBuff->decRate*R2D, iMBuff->rateAge);
     1069      double avRate = sqrt(cAvRate[0]*cAvRate[0] + cAvRate[1]*cAvRate[1]);
     1070      fprintf(stderr, "RA, Dec, Av & PA rates: %8.4f %8.4f %8.4f %8.4f "
     1071        "pCode %d\n", raRate*R2D, decRate*R2D, avRate*R2D, paRate*R2D, pCode);
    8501072#endif
     1073
    8511074
    8521075      // Compute the position of this beam for all bins.
     
    8561079        cBuffer[jbuff].raRate  = iMBuff->raRate;
    8571080        cBuffer[jbuff].decRate = iMBuff->decRate;
    858 
    859         double dutc = cBuffer[jbuff].utc - thisUTC;
    860         if (dutc > 100.0) {
     1081        cBuffer[jbuff].paRate  = iMBuff->paRate;
     1082
     1083        double dUTC = utcDiff(cBuffer[jbuff].utc, thisUTC);
     1084        if (dUTC > 100.0) {
    8611085          // Must have cycled through midnight.
    862           dutc -= 86400.0;
    863         }
    864 
    865         cBuffer[jbuff].ra  = thisRA  + cBuffer[jbuff].raRate  * dutc;
    866         cBuffer[jbuff].dec = thisDec + cBuffer[jbuff].decRate * dutc;
    867         if (cBuffer[jbuff].ra < 0.0) {
    868           cBuffer[jbuff].ra += TWOPI;
    869         } else if (cBuffer[jbuff].ra > TWOPI) {
    870           cBuffer[jbuff].ra -= TWOPI;
    871         }
     1086          dUTC -= 86400.0;
     1087        }
     1088
     1089        applyRate(cRA0, cDec0, thisRA, thisDec,
     1090          cBuffer[jbuff].raRate, cBuffer[jbuff].decRate, dUTC,
     1091          cBuffer[jbuff].ra, cBuffer[jbuff].dec);
     1092
     1093#ifdef PKSIO_DEBUG
     1094        fprintf(stderr, "Intp (%d) ra, dec, UTC: %9.4f %9.4f %10.3f (pCode, "
     1095          "age: %d %.1fs)\n", iMBuff->cycleNo, cBuffer[jbuff].ra*R2D,
     1096          cBuffer[jbuff].dec*R2D, cBuffer[jbuff].utc, iMBuff->pCode,
     1097          iMBuff->rateAge);
     1098#endif
    8721099      }
    8731100    }
     
    8801107
    8811108#ifdef PKSIO_DEBUG
    882       printf("Out:%4d%4d%3d%3d\n", MBrec.scanNo, MBrec.cycleNo, MBrec.beamNo,
    883         MBrec.IFno[0]);
     1109      fprintf(stderr, "Out:%4d%4d%3d%3d\n", MBrec.scanNo, MBrec.cycleNo,
     1110        MBrec.beamNo, MBrec.IFno[0]);
    8841111#endif
    8851112
     
    9231150        // Sanity check on the number of IFs in the new scan.
    9241151        if (if_.n_if != cNIF) {
    925           fprintf(stderr, "WARNING, scan %d has %d IFs instead of %d, "
    926             "continuing.\n", cScanNo, if_.n_if, cNIF);
     1152          sprintf(cMsg, "WARNING: Scan %d has %d IFs instead of %d, "
     1153            "continuing.", cScanNo, if_.n_if, cNIF);
     1154          logMsg(cMsg);
    9271155        }
    9281156      }
     
    9351163      }
    9361164
    937       iMBuff->scanNo  = cScanNo;
    938       iMBuff->cycleNo = cCycleNo;
    939 
    940       // Times.
    941       strncpy(iMBuff->datobs, cDateObs, 10);
    942       iMBuff->utc = cUTC;
    943       iMBuff->exposure = param_.intbase;
    944 
    945       // Source identification.
    946       sprintf(iMBuff->srcName, "%-16.16s",
    947               names_.su_name + (cSrcNo-1)*16);
    948       iMBuff->srcRA  = doubles_.su_ra[cSrcNo-1];
    949       iMBuff->srcDec = doubles_.su_dec[cSrcNo-1];
    950 
    951       // Rest frequency of the line of interest.
    952       iMBuff->restFreq = doubles_.rfreq;
    953       if (strncmp(names_.instrument, "ATPKSMB", 7) == 0) {
    954         // Fix the HI rest frequency recorded for Parkes multibeam data.
    955         double reffreq  = doubles_.freq;
    956         double restfreq = doubles_.rfreq;
    957         if ((restfreq == 0.0 || fabs(restfreq - reffreq) == 0.0) &&
    958              fabs(reffreq - 1420.40575e6) < 100.0) {
    959           iMBuff->restFreq = 1420.40575e6;
    960         }
    961       }
    962 
    963       // Observation type.
    964       int j;
    965       for (j = 0; j < 15; j++) {
    966         iMBuff->obsType[j] = names_.card[11+j];
    967         if (iMBuff->obsType[j] == '\'') break;
    968       }
    969       iMBuff->obsType[j] = '\0';
    970 
    971       // Beam-dependent parameters.
    972       iMBuff->beamNo = beamNo;
    973 
    974       // Beam position at the specified time.
    975       if (cSUpos) {
    976         // Non-ATNF data that does not store the position in (u,v,w).
    977         iMBuff->ra  = doubles_.su_ra[cSrcNo-1];
    978         iMBuff->dec = doubles_.su_dec[cSrcNo-1];
    979       } else {
    980         iMBuff->ra  = cU;
    981         iMBuff->dec = cV;
    982       }
    983       cPosUTC[iBeamSel] = cW;
     1165#ifdef PKSIO_DEBUG
     1166      fprintf(stderr, "Buf:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, cIFno);
     1167#endif
     1168
     1169      // Store IF-independent parameters only for the first IF of a new cycle,
     1170      // particularly because this is the only one for which the scan rates
     1171      // are computed above.
     1172      int firstIF = (iMBuff->nIF == 0);
     1173      if (firstIF) {
     1174        iMBuff->scanNo  = cScanNo;
     1175        iMBuff->cycleNo = cCycleNo;
     1176
     1177        // Times.
     1178        strcpy(iMBuff->datobs, cDateObs);
     1179        iMBuff->utc = cUTC;
     1180        iMBuff->exposure = param_.intbase;
     1181
     1182        // Source identification.
     1183        sprintf(iMBuff->srcName, "%-16.16s",
     1184                names_.su_name + (cSrcNo-1)*16);
     1185        iMBuff->srcName[16] = '\0';
     1186        iMBuff->srcRA  = doubles_.su_ra[cSrcNo-1];
     1187        iMBuff->srcDec = doubles_.su_dec[cSrcNo-1];
     1188
     1189        // Rest frequency of the line of interest.
     1190        iMBuff->restFreq = doubles_.rfreq;
     1191        if (strncmp(names_.instrument, "ATPKSMB", 7) == 0) {
     1192          // Fix the HI rest frequency recorded for Parkes multibeam data.
     1193          double reffreq  = doubles_.freq;
     1194          double restfreq = doubles_.rfreq;
     1195          if ((restfreq == 0.0 || fabs(restfreq - reffreq) == 0.0) &&
     1196               fabs(reffreq - 1420.405752e6) < 100.0) {
     1197            iMBuff->restFreq = 1420.405752e6;
     1198          }
     1199        }
     1200
     1201        // Observation type.
     1202        int j;
     1203        for (j = 0; j < 15; j++) {
     1204          iMBuff->obsType[j] = names_.card[11+j];
     1205          if (iMBuff->obsType[j] == '\'') break;
     1206        }
     1207        iMBuff->obsType[j] = '\0';
     1208
     1209        // Beam-dependent parameters.
     1210        iMBuff->beamNo = beamNo;
     1211
     1212        // Beam position at the specified time.
     1213        if (cSUpos) {
     1214          // Non-ATNF data that does not store the position in (u,v,w).
     1215          iMBuff->ra  = doubles_.su_ra[cSrcNo-1];
     1216          iMBuff->dec = doubles_.su_dec[cSrcNo-1];
     1217        } else {
     1218          iMBuff->ra  = cU;
     1219          iMBuff->dec = cV;
     1220        }
     1221        cPosUTC[iBeamSel] = cW;
     1222        iMBuff->pCode = pCode;
     1223
     1224        // Store rates for next time.
     1225        iMBuff->raRate  =  raRate;
     1226        iMBuff->decRate = decRate;
     1227        iMBuff->paRate  =  paRate;
     1228      }
    9841229
    9851230      // IF-dependent parameters.
     
    9921237
    9931238      iIFSel = cIFSel[iIF];
    994       iMBuff->nIF++;
    995       iMBuff->IFno[iIFSel]  = cIFno;
     1239      if (iMBuff->IFno[iIFSel] == 0) {
     1240        iMBuff->nIF++;
     1241        iMBuff->IFno[iIFSel] = cIFno;
     1242      } else {
     1243        // Integration cycle written to the output file twice (the only known
     1244        // example is 1999-05-22_1914_000-031805_03v.hpf).
     1245        sprintf(cMsg, "WARNING: Integration cycle %d:%d, beam %2d, \n"
     1246                      "         IF %d was duplicated.", cScanNo, cCycleNo-1,
     1247                      beamNo, cIFno);
     1248        logMsg(cMsg);
     1249      }
    9961250      iMBuff->nChan[iIFSel] = nChan;
    9971251      iMBuff->nPol[iIFSel]  = cNPol[iIF];
     
    10931347
    10941348
    1095       // Parallactic angle.
    1096       iMBuff->parAngle = sc_.sc_cal[scq*iBeam + 11];
    1097 
    10981349      // Calibration factor applied to the data by the correlator.
    10991350      if (scq > 14) {
     
    11061357      }
    11071358
    1108       if (sc_.sc_ant <= anten_.nant) {
    1109         // No extra syscal information present.
    1110         iMBuff->extraSysCal = 0;
    1111         iMBuff->azimuth   = 0.0f;
    1112         iMBuff->elevation = 0.0f;
    1113         iMBuff->parAngle  = 0.0f;
    1114         iMBuff->focusAxi  = 0.0f;
    1115         iMBuff->focusTan  = 0.0f;
    1116         iMBuff->focusRot  = 0.0f;
    1117         iMBuff->temp      = 0.0f;
    1118         iMBuff->pressure  = 0.0f;
    1119         iMBuff->humidity  = 0.0f;
    1120         iMBuff->windSpeed = 0.0f;
    1121         iMBuff->windAz    = 0.0f;
    1122         strcpy(iMBuff->tcalTime, "                ");
    1123         iMBuff->refBeam = 0;
    1124 
    1125       } else {
    1126         // Additional information for Parkes Multibeam data.
    1127         int iOff = scq*(sc_.sc_ant - 1) - 1;
    1128         iMBuff->extraSysCal = 1;
    1129         iMBuff->azimuth   = sc_.sc_cal[iOff + 2];
    1130         iMBuff->elevation = sc_.sc_cal[iOff + 3];
    1131         iMBuff->parAngle  = sc_.sc_cal[iOff + 4];
    1132         iMBuff->focusAxi  = sc_.sc_cal[iOff + 5] * 1e-3;
    1133         iMBuff->focusTan  = sc_.sc_cal[iOff + 6] * 1e-3;
    1134         iMBuff->focusRot  = sc_.sc_cal[iOff + 7];
    1135         iMBuff->temp      = sc_.sc_cal[iOff + 8];
    1136         iMBuff->pressure  = sc_.sc_cal[iOff + 9];
    1137         iMBuff->humidity  = sc_.sc_cal[iOff + 10];
    1138         iMBuff->windSpeed = sc_.sc_cal[iOff + 11];
    1139         iMBuff->windAz    = sc_.sc_cal[iOff + 12];
    1140 
    1141         char *tcalTime = iMBuff->tcalTime;
    1142         sprintf(tcalTime, "%-16.16s", (char *)(&sc_.sc_cal[iOff+13]));
     1359      if (firstIF) {
     1360        if (sc_.sc_ant <= anten_.nant) {
     1361          // No extra syscal information present.
     1362          iMBuff->extraSysCal = 0;
     1363          iMBuff->azimuth   = 0.0f;
     1364          iMBuff->elevation = 0.0f;
     1365          iMBuff->parAngle  = 0.0f;
     1366          iMBuff->focusAxi  = 0.0f;
     1367          iMBuff->focusTan  = 0.0f;
     1368          iMBuff->focusRot  = 0.0f;
     1369          iMBuff->temp      = 0.0f;
     1370          iMBuff->pressure  = 0.0f;
     1371          iMBuff->humidity  = 0.0f;
     1372          iMBuff->windSpeed = 0.0f;
     1373          iMBuff->windAz    = 0.0f;
     1374          strcpy(iMBuff->tcalTime, "                ");
     1375          iMBuff->refBeam = 0;
     1376
     1377        } else {
     1378          // Additional information for Parkes Multibeam data.
     1379          int iOff = scq*(sc_.sc_ant - 1) - 1;
     1380          iMBuff->extraSysCal = 1;
     1381
     1382          iMBuff->azimuth   = sc_.sc_cal[iOff + 2];
     1383          iMBuff->elevation = sc_.sc_cal[iOff + 3];
     1384          iMBuff->parAngle  = sc_.sc_cal[iOff + 4];
     1385
     1386          iMBuff->focusAxi  = sc_.sc_cal[iOff + 5] * 1e-3;
     1387          iMBuff->focusTan  = sc_.sc_cal[iOff + 6] * 1e-3;
     1388          iMBuff->focusRot  = sc_.sc_cal[iOff + 7];
     1389
     1390          iMBuff->temp      = sc_.sc_cal[iOff + 8];
     1391          iMBuff->pressure  = sc_.sc_cal[iOff + 9];
     1392          iMBuff->humidity  = sc_.sc_cal[iOff + 10];
     1393          iMBuff->windSpeed = sc_.sc_cal[iOff + 11];
     1394          iMBuff->windAz    = sc_.sc_cal[iOff + 12];
     1395
     1396          char *tcalTime = iMBuff->tcalTime;
     1397          sprintf(tcalTime, "%-16.16s", (char *)(&sc_.sc_cal[iOff+13]));
     1398          tcalTime[16] = '\0';
    11431399
    11441400#ifndef AIPS_LITTLE_ENDIAN
    1145         // Do byte swapping on the ASCII date string.
    1146         for (int j = 0; j < 16; j += 4) {
    1147           char ctmp;
    1148           ctmp = tcalTime[j];
    1149           tcalTime[j]   = tcalTime[j+3];
    1150           tcalTime[j+3] = ctmp;
    1151           ctmp = tcalTime[j+1];
    1152           tcalTime[j+1] = tcalTime[j+2];
    1153           tcalTime[j+2] = ctmp;
    1154         }
     1401          // Do byte swapping on the ASCII date string.
     1402          for (int j = 0; j < 16; j += 4) {
     1403            char ctmp;
     1404            ctmp = tcalTime[j];
     1405            tcalTime[j]   = tcalTime[j+3];
     1406            tcalTime[j+3] = ctmp;
     1407            ctmp = tcalTime[j+1];
     1408            tcalTime[j+1] = tcalTime[j+2];
     1409            tcalTime[j+2] = ctmp;
     1410          }
    11551411#endif
    11561412
    1157         // Reference beam number.
    1158         float refbeam = sc_.sc_cal[iOff + 17];
    1159         if (refbeam > 0.0f || refbeam < 100.0f) {
    1160           iMBuff->refBeam = int(refbeam);
    1161         } else {
    1162           iMBuff->refBeam = 0;
     1413          // Reference beam number.
     1414          float refbeam = sc_.sc_cal[iOff + 17];
     1415          if (refbeam > 0.0f || refbeam < 100.0f) {
     1416            iMBuff->refBeam = int(refbeam);
     1417          } else {
     1418            iMBuff->refBeam = 0;
     1419          }
    11631420        }
    11641421      }
     
    11851442  while (numErr < 10) {
    11861443    int lastjstat = jstat;
    1187     rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
    1188               &cBin, &cIFno, &cSrcNo);
    1189 
    1190     switch(jstat) {
     1444
     1445    switch(rpfitsin(jstat)) {
    11911446    case -1:
    11921447      // Read failed; retry.
    11931448      numErr++;
    1194       fprintf(stderr, "RPFITS read failed - retrying.\n");
     1449      logMsg("WARNING: RPFITS read failed - retrying.");
    11951450      jstat = 0;
    11961451      break;
     
    12481503    default:
    12491504      // Shouldn't reach here.
    1250       fprintf(stderr, "Unrecognized RPFITSIN return code: %d (retrying)\n",
    1251               jstat);
     1505      sprintf(cMsg, "WARNING: Unrecognized RPFITSIN return code: %d "
     1506                    "(retrying).", jstat);
     1507      logMsg(cMsg);
    12521508      jstat = 0;
    12531509      break;
     
    12551511  }
    12561512
    1257   fprintf(stderr, "ERROR, RPFITS read failed too many times.\n");
     1513  logMsg("ERROR: RPFITS read failed too many times.");
    12581514  return 2;
     1515}
     1516
     1517//----------------------------------------------------- MBFITSreader::rpfitsin
     1518
     1519// Wrapper around RPFITSIN that reports errors.  Returned RPFITSIN subroutine
     1520// arguments are captured as MBFITSreader member variables.
     1521
     1522int MBFITSreader::rpfitsin(int &jstat)
     1523
     1524{
     1525  rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
     1526            &cBin, &cIFno, &cSrcNo);
     1527
     1528  // Handle messages from RPFITSIN.
     1529  if (names_.errmsg[0] != ' ') {
     1530    int i;
     1531    for (i = 80; i > 0; i--) {
     1532      if (names_.errmsg[i-1] != ' ') break;
     1533    }
     1534
     1535    sprintf(cMsg, "WARNING: Cycle %d:%03d, RPFITSIN reported -\n"
     1536                  "         %.*s", cScanNo, cCycleNo, i, names_.errmsg);
     1537    logMsg(cMsg);
     1538  }
     1539
     1540  return jstat;
     1541}
     1542
     1543//------------------------------------------------------- MBFITSreader::fixPos
     1544
     1545// Check and, if necessary, repair a position timestamp.
     1546//
     1547// Problems with the position timestamp manifest themselves via the scan rate:
     1548//
     1549//   1) Zero scan rate pairs, 1997/02/28 to 1998/01/07
     1550//
     1551//      These occur because the position timestamp for the first integration
     1552//      of the pair is erroneous; the value recorded is t/1000, where t is the
     1553//      true value.
     1554//        Earliest known: 97-02-28_1725_132653-42_258a.hpf
     1555//          Latest known: 98-01-02_1923_095644-50_165c.hpf
     1556//        (time range chosen to encompass observing runs).
     1557//
     1558//   2) Slow-fast scan rate pairs (0.013 - 0.020 deg/s),
     1559//        1997/03/28 to 1998/01/07.
     1560//
     1561//      The UTC position timestamp is 1.0s later than it should be (never
     1562//      earlier), almost certainly arising from an error in the telescope
     1563//      control system.
     1564//        Earliest known: 97-03-28_0150_010420-74_008d.hpf
     1565//          Latest known: 98-01-04_1502_065150-02_177c.hpf
     1566//        (time range chosen to encompass observing runs).
     1567//
     1568//   3) Slow-fast scan rate pairs (0.015 - 0.018 deg/s),
     1569//        1999/05/20 to 2001/07/12 (HIPASS and ZOA),
     1570//        2001/09/02 to 2001/12/04 (HIPASS and ZOA),
     1571//        2002/03/28 to 2002/05/13 (ZOA only),
     1572//        2003/04/26 to 2003/06/09 (ZOA only).
     1573//        Earliest known: 1999-05-20_1818_175720-50_297e.hpf
     1574//          Latest known: 2001-12-04_1814_065531p14_173e.hpf (HIPASS)
     1575//                        2003-06-09_1924_352-085940_-6c.hpf (ZOA)
     1576//
     1577//      Caused by the Linux signalling NaN problem.  IEEE "signalling" NaNs
     1578//      are silently transformed to "quiet" NaNs during assignment by setting
     1579//      bit 22.  This affected RPFITS because of its use of VAX-format
     1580//      floating-point numbers which, with their permuted bytes, may sometimes
     1581//      appear as signalling NaNs.
     1582//
     1583//      The problem arose when the linux correlator came online and was
     1584//      fixed with a workaround to the RPFITS library (repeated episodes
     1585//      are probably due to use of an older version of the library).  It
     1586//      should not have affected the data significantly because of the
     1587//      low relative error, which ranges from 0.0000038 to 0.0000076, but
     1588//      it is important for the computation of scan rates which requires
     1589//      taking the difference of two large UTC timestamps, one or other
     1590//      of which will have 0.5s added to it.
     1591//
     1592// The return value identifies which, if any, of these problems was repaired.
     1593
     1594int MBFITSreader::fixw(
     1595  const char *datobs,
     1596  int    cycleNo,
     1597  int    beamNo,
     1598  double avRate[2],
     1599  double thisRA,
     1600  double thisDec,
     1601  double thisUTC,
     1602  double nextRA,
     1603  double nextDec,
     1604  float &nextUTC)
     1605{
     1606  if (strcmp(datobs, "2003-06-09") > 0) {
     1607    return 0;
     1608
     1609  } else if (strcmp(datobs, "1998-01-07") <= 0) {
     1610    if (nextUTC < thisUTC && (nextUTC + 86400.0) > (thisUTC + 600.0)) {
     1611      // Possible scaling problem.
     1612      double diff = nextUTC*1000.0 - thisUTC;
     1613      if (0.0 < diff && diff < 600.0) {
     1614        nextUTC *= 1000.0;
     1615        return 1;
     1616      } else {
     1617        // Irreparable.
     1618        return -1;
     1619      }
     1620    }
     1621
     1622    if (cycleNo > 2) {
     1623      if (beamNo == 1) {
     1624        // This test is only reliable for beam 1.
     1625        double dUTC = nextUTC - thisUTC;
     1626        if (dUTC < 0.0) dUTC += 86400.0;
     1627
     1628        // Guard against RA cycling through 24h in either direction.
     1629        if (fabs(nextRA - thisRA) > PI) {
     1630          if (nextRA < thisRA) {
     1631            nextRA += TWOPI;
     1632          } else {
     1633            nextRA -= TWOPI;
     1634          }
     1635        }
     1636
     1637        double  dRA = (nextRA  - thisRA) * cos(nextDec);
     1638        double dDec =  nextDec - thisDec;
     1639        double  arc = sqrt(dRA*dRA + dDec*dDec);
     1640
     1641        double averate = sqrt(avRate[0]*avRate[0] + avRate[1]*avRate[1]);
     1642        double diff1 = fabs(averate - arc/(dUTC-1.0));
     1643        double diff2 = fabs(averate - arc/dUTC);
     1644        if ((diff1 < diff2) && (diff1 < 0.05*averate)) {
     1645          nextUTC -= 1.0;
     1646          cCode5 = cycleNo;
     1647          return 2;
     1648        } else {
     1649          cCode5 = 0;
     1650        }
     1651
     1652      } else {
     1653        if (cycleNo == cCode5) {
     1654          nextUTC -= 1.0;
     1655          return 2;
     1656        }
     1657      }
     1658    }
     1659
     1660  } else if ((strcmp(datobs, "1999-05-20") >= 0 &&
     1661              strcmp(datobs, "2001-07-12") <= 0) ||
     1662             (strcmp(datobs, "2001-09-02") >= 0 &&
     1663              strcmp(datobs, "2001-12-04") <= 0) ||
     1664             (strcmp(datobs, "2002-03-28") >= 0 &&
     1665              strcmp(datobs, "2002-05-13") <= 0) ||
     1666             (strcmp(datobs, "2003-04-26") >= 0 &&
     1667              strcmp(datobs, "2003-06-09") <= 0)) {
     1668    // Signalling NaN problem, e.g. 1999-07-26_1839_011106-74_009c.hpf.
     1669    // Position timestamps should always be an integral number of seconds.
     1670    double resid = nextUTC - int(nextUTC);
     1671    if (resid == 0.5) {
     1672      nextUTC -= 0.5;
     1673      return 3;
     1674    }
     1675  }
     1676
     1677  return 0;
    12591678}
    12601679
     
    12921711  }
    12931712}
     1713
     1714//-------------------------------------------------------------------- utcDiff
     1715
     1716// Subtract two UTCs (s) allowing for any plausible number of cycles through
     1717// 86400s, returning a result in the range [-43200, +43200]s.
     1718
     1719double MBFITSreader::utcDiff(double utc1, double utc2)
     1720{
     1721  double diff = utc1 - utc2;
     1722
     1723  if (diff > 43200.0) {
     1724    diff -= 86400.0;
     1725    while (diff > 43200.0) diff -= 86400.0;
     1726  } else if (diff < -43200.0) {
     1727    diff += 86400.0;
     1728    while (diff < -43200.0) diff += 86400.0;
     1729  }
     1730
     1731  return diff;
     1732}
     1733
     1734//------------------------------------------------------- scanRate & applyRate
     1735
     1736// Compute and apply the scan rate corrected for grid convergence.  (ra0,dec0)
     1737// are the coordinates of the central beam, assumed to be the tracking centre.
     1738// The rate computed in RA will be a rate of change of angular distance in the
     1739// direction of increasing RA at the position of the central beam.  Similarly
     1740// for declination.  Angles in radian, time in s.
     1741
     1742void MBFITSreader::scanRate(
     1743  double ra0,
     1744  double dec0,
     1745  double ra1,
     1746  double dec1,
     1747  double ra2,
     1748  double dec2,
     1749  double dt,
     1750  double &raRate,
     1751  double &decRate)
     1752{
     1753  // Transform to a system where the central beam lies on the equator at 12h.
     1754  eulerx(ra1, dec1, ra0+HALFPI, -dec0, -HALFPI, ra1, dec1);
     1755  eulerx(ra2, dec2, ra0+HALFPI, -dec0, -HALFPI, ra2, dec2);
     1756
     1757  raRate  = (ra2  - ra1)  / dt;
     1758  decRate = (dec2 - dec1) / dt;
     1759}
     1760
     1761
     1762void MBFITSreader::applyRate(
     1763  double ra0,
     1764  double dec0,
     1765  double ra1,
     1766  double dec1,
     1767  double raRate,
     1768  double decRate,
     1769  double dt,
     1770  double &ra2,
     1771  double &dec2)
     1772{
     1773  // Transform to a system where the central beam lies on the equator at 12h.
     1774  eulerx(ra1, dec1, ra0+HALFPI, -dec0, -HALFPI, ra1, dec1);
     1775
     1776  ra2  = ra1  + (raRate  * dt);
     1777  dec2 = dec1 + (decRate * dt);
     1778
     1779  // Transform back.
     1780  eulerx(ra2, dec2, -HALFPI, dec0, ra0+HALFPI, ra2, dec2);
     1781}
     1782
     1783//--------------------------------------------------------------------- eulerx
     1784
     1785void MBFITSreader::eulerx(
     1786  double lng0,
     1787  double lat0,
     1788  double phi0,
     1789  double theta,
     1790  double phi,
     1791  double &lng1,
     1792  double &lat1)
     1793
     1794// Applies the Euler angle based transformation of spherical coordinates.
     1795//
     1796//     phi0  Longitude of the ascending node in the old system, radians.  The
     1797//           ascending node is the point of intersection of the equators of
     1798//           the two systems such that the equator of the new system crosses
     1799//           from south to north as viewed in the old system.
     1800//
     1801//    theta  Angle between the poles of the two systems, radians.  THETA is
     1802//           positive for a positive rotation about the ascending node.
     1803//
     1804//      phi  Longitude of the ascending node in the new system, radians.
     1805
     1806{
     1807  // Compute intermediaries.
     1808  double lng0p  = lng0 - phi0;
     1809  double slng0p = sin(lng0p);
     1810  double clng0p = cos(lng0p);
     1811  double slat0  = sin(lat0);
     1812  double clat0  = cos(lat0);
     1813  double ctheta = cos(theta);
     1814  double stheta = sin(theta);
     1815
     1816  double x = clat0*clng0p;
     1817  double y = clat0*slng0p*ctheta + slat0*stheta;
     1818
     1819  // Longitude in the new system.
     1820  if (x != 0.0 || y != 0.0) {
     1821    lng1 = phi + atan2(y, x);
     1822  } else {
     1823    // Longitude at the poles in the new system is consistent with that
     1824    // specified in the old system.
     1825    lng1 = phi + lng0p;
     1826  }
     1827  lng1 = fmod(lng1, TWOPI);
     1828  if (lng1 < 0.0) lng1 += TWOPI;
     1829
     1830  lat1 = asin(slat0*ctheta - clat0*stheta*slng0p);
     1831}
Note: See TracChangeset for help on using the changeset viewer.