Ignore:
Timestamp:
06/09/10 19:03:06 (14 years ago)
Author:
Kana Sugimoto
Message:

New Development: Yes

JIRA Issue: Yes (CAS-2211)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: ASAP 3.0.0 interface changes

Test Programs:

Put in Release Notes: Yes

Module(s): all the CASA sd tools and tasks are affected.

Description: Merged ATNF-ASAP 3.0.0 developments to CASA (alma) branch.

Note you also need to update casa/code/atnf.


Location:
branches/alma
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/alma

  • branches/alma/external/atnf/PKSIO/MBFITSreader.cc

    r1453 r1757  
    22//# MBFITSreader.cc: ATNF single-dish RPFITS reader.
    33//#---------------------------------------------------------------------------
    4 //# Copyright (C) 2000-2006
    5 //# Mark Calabretta, ATNF
     4//# livedata - processing pipeline for single-dish, multibeam spectral data.
     5//# Copyright (C) 2000-2009, Australia Telescope National Facility, CSIRO
    66//#
    7 //# This library is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU Library General Public License as published by
    9 //# the Free Software Foundation; either version 2 of the License, or (at your
    10 //# option) any later version.
     7//# This file is part of livedata.
    118//#
    12 //# This library is distributed in the hope that it will be useful, but WITHOUT
     9//# livedata is free software: you can redistribute it and/or modify it under
     10//# the terms of the GNU General Public License as published by the Free
     11//# Software Foundation, either version 3 of the License, or (at your option)
     12//# any later version.
     13//#
     14//# livedata is distributed in the hope that it will be useful, but WITHOUT
    1315//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    14 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    15 //# License for more details.
     16//# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     17//# more details.
    1618//#
    17 //# You should have received a copy of the GNU Library General Public License
    18 //# along with this library; if not, write to the Free Software Foundation,
    19 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
     19//# You should have received a copy of the GNU General Public License along
     20//# with livedata.  If not, see <http://www.gnu.org/licenses/>.
    2021//#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: mcalabre@atnf.csiro.au.
    23 //#        Postal address: Dr. Mark Calabretta,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
     22//# Correspondence concerning livedata may be directed to:
     23//#        Internet email: mcalabre@atnf.csiro.au
     24//#        Postal address: Dr. Mark Calabretta
     25//#                        Australia Telescope National Facility, CSIRO
     26//#                        PO Box 76
     27//#                        Epping NSW 1710
    2728//#                        AUSTRALIA
    2829//#
    29 //# $Id$
     30//# http://www.atnf.csiro.au/computing/software/livedata.html
     31//# $Id: MBFITSreader.cc,v 19.57 2009-10-30 06:34:36 cal103 Exp $
    3032//#---------------------------------------------------------------------------
    3133//# The MBFITSreader class reads single dish RPFITS files (such as Parkes
     
    3537//#---------------------------------------------------------------------------
    3638
     39#include <atnf/pks/pks_maths.h>
    3740#include <atnf/PKSIO/MBFITSreader.h>
    38 #include <atnf/PKSIO/PKSMBrecord.h>
    39 
    40 #include <RPFITS.h>
     41#include <atnf/PKSIO/MBrecord.h>
     42
     43#include <casa/Logging/LogIO.h>
    4144
    4245#include <casa/math.h>
     
    4750#include <unistd.h>
    4851
     52#include <RPFITS.h>
     53
    4954using namespace std;
    5055
     
    5257const double PI = 3.141592653589793238462643;
    5358const double TWOPI = 2.0 * PI;
     59const double HALFPI = PI / 2.0;
     60const double R2D = 180.0 / PI;
     61
     62// Class name
     63const string className = "MBFITSreader" ;
    5464
    5565//------------------------------------------------- MBFITSreader::MBFITSreader
     
    8191  cRefChan   = 0x0;
    8292
    83   cVis = new float[2*4*8163];
     93  cVis = 0x0;
     94  cWgt = 0x0;
    8495
    8596  cBeamSel   = 0x0;
     
    91102
    92103  cMBopen = 0;
    93   jstat = -3;
     104
     105  // Tell RPFITSIN not to report errors directly.
     106  //iostat_.errlun = -1;
    94107}
    95108
     
    120133        int  &extraSysCal)
    121134{
     135  const string methodName = "open()" ;
     136  LogIO os( LogOrigin( className, methodName, WHERE ) ) ;
     137
    122138  if (cMBopen) {
    123139    close();
     
    127143
    128144  // Open the RPFITS file.
    129   rpfitsin_(&jstat, cVis, weight, &baseline, &ut, &u, &v, &w, &flag, &bin,
    130             &if_no, &sourceno);
    131 
    132   if (jstat) {
    133     fprintf(stderr, "Failed to open MBFITS file: %s\n", rpname);
     145  int jstat = -3;
     146  if (rpfitsin(jstat)) {
     147    sprintf(cMsg, "Failed to open MBFITS file\n%s", rpname);
     148    os << LogIO::SEVERE << cMsg << LogIO::POST ;
    134149    return 1;
    135150  }
     
    147162  // Read the first header.
    148163  jstat = -1;
    149   rpfitsin_(&jstat, cVis, weight, &baseline, &ut, &u, &v, &w, &flag, &bin,
    150             &if_no, &sourceno);
    151 
    152   if (jstat) {
    153     fprintf(stderr, "Failed to read MBFITS header: %s\n", rpname);
     164  if (rpfitsin(jstat)) {
     165    sprintf(cMsg, "Failed to read MBFITS header in file\n"
     166                  "%s", rpname);
     167    os << LogIO::SEVERE << cMsg << LogIO::POST ;
    154168    close();
    155169    return 1;
     
    159173  cMopra = strncmp(names_.instrument, "ATMOPRA", 7) == 0;
    160174
    161   // Tidbinbilla data has some more.
    162   cTid = strncmp(names_.sta, "tid", 3) == 0;
    163   if (cTid) {
    164     // Telescope position is stored in the source table.
     175  // Non-ATNF data may not store the position in (u,v,w).
     176  if (strncmp(names_.sta, "tid", 3) == 0) {
     177    sprintf(cMsg, "Found Tidbinbilla data");
     178    cSUpos = 1;
     179  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
     180    sprintf(cMsg, "Found Hobart data");
     181    cSUpos = 1;
     182  } else if (strncmp(names_.sta, "CED", 3) == 0) {
     183    sprintf(cMsg, "Found Ceduna data");
     184    cSUpos = 1;
     185  } else {
     186    cSUpos = 0;
     187  }
     188
     189  if (cSUpos) {
     190    strcat(cMsg, ", using telescope position\n         from SU table.");
     191    os << LogIO::WARN << cMsg << LogIO::POST ;
    165192    cInterp = 0;
    166193  }
     194
     195  // Mean scan rate (for timestamp repairs).
     196  cNRate = 0;
     197  cAvRate[0] = 0.0;
     198  cAvRate[1] = 0.0;
     199  cCode5 = 0;
    167200
    168201
     
    176209
    177210  if (cNBeam <= 0) {
    178     fprintf(stderr, "Couldn't determine number of beams.\n");
     211    os << LogIO::SEVERE << "Couldn't determine number of beams." << LogIO::POST ;
    179212    close();
    180213    return 1;
     
    189222  // ...beams present in the data.
    190223  for (int iBeam = 0; iBeam < anten_.nant; iBeam++) {
    191     cBeams[anten_.ant_num[iBeam] - 1] = 1;
     224    // Guard against dubious beam numbers, e.g. zeroes in
     225    // 1999-09-29_1632_024848p14_071b.hpf and the four scans following.
     226    // Note that the actual beam number is decoded from the 'baseline' random
     227    // parameter for each spectrum and is only used for beam selection.
     228    int beamNo = anten_.ant_num[iBeam];
     229    if (beamNo != iBeam+1) {
     230      char sta[8];
     231      strncpy(sta, names_.sta+(8*iBeam), 8);
     232      char *cp = sta + 7;
     233      while (*cp == ' ') *(cp--) = '\0';
     234
     235      sprintf(cMsg,
     236        "RPFITSIN returned beam number %2d for AN table\n"
     237        "entry %2d with name '%.8s'", beamNo, iBeam+1, sta);
     238
     239      char text[8];
     240      sprintf(text, "MB%2.2d", iBeam+1);
     241      cp = cMsg + strlen(cMsg);
     242      if (strncmp(sta, text, 8) == 0) {
     243        beamNo = iBeam + 1;
     244        sprintf(cp, "; using beam number %2d.", beamNo);
     245      } else {
     246        sprintf(cp, ".");
     247      }
     248
     249      os << LogIO::WARN << cMsg << LogIO::POST ;
     250    }
     251
     252    if (0 < beamNo && beamNo <= cNBeam) {
     253      cBeams[beamNo-1] = 1;
     254    }
    192255  }
    193256
     
    237300  }
    238301
    239   // Is the vis array declared by RPFITS.h large enough?
    240   if (8*8193 < maxProd) {
    241     // Need to allocate more memory for RPFITSIN.
    242     cVis = new float[2*maxProd];
    243   }
     302  // Allocate memory for RPFITSIN subroutine arguments.
     303  if (cVis) delete [] cVis;
     304  if (cWgt) delete [] cWgt;
     305  cVis = new float[2*maxProd];
     306  cWgt = new float[maxProd];
    244307
    245308  nChan    = cNChan;
     
    278341  // Read the first syscal record.
    279342  if (rpget(1, cEOS)) {
    280     fprintf(stderr, "Error: Failed to read first syscal record.\n");
     343    os << LogIO::SEVERE << "Failed to read first syscal record." << LogIO::POST ;
    281344    close();
    282345    return 1;
     
    304367        double antPos[3],
    305368        char   obsType[32],
     369        char   bunit[32],
    306370        float  &equinox,
    307371        char   radecsys[32],
     
    312376        double &bandwidth)
    313377{
     378  const string methodName = "getHeader()" ;
     379  LogIO os( LogOrigin( className, methodName, WHERE ) ) ;
     380
    314381  if (!cMBopen) {
    315     fprintf(stderr, "An MBFITS file has not been opened.\n");
     382    os << LogIO::SEVERE << "An MBFITS file has not been opened." << LogIO::POST ;
    316383    return 1;
    317384  }
     
    333400    antPos[1] =  2816759.046;
    334401    antPos[2] = -3454035.950;
     402
    335403  } else if (strncmp(names_.sta, "HOH", 3) == 0) {
    336404    // Parkes HOH receiver.
     
    339407    antPos[1] =  2816759.046;
    340408    antPos[2] = -3454035.950;
     409
    341410  } else if (strncmp(names_.sta, "CA0", 3) == 0) {
    342411    // An ATCA antenna, use the array centre position.
     
    345414    antPos[1] =  2792906.182;
    346415    antPos[2] = -3200483.747;
     416
     417    // ATCA-104.  Updated position at epoch 2007/06/24 from Chris Phillips.
     418    // antPos[0] = -4751640.182; // ± 0.008
     419    // antPos[1] =  2791700.322; // ± 0.006
     420    // antPos[2] = -3200490.668; // ± 0.007
     421    //
    347422  } else if (strncmp(names_.sta, "MOP", 3) == 0) {
    348     // Mopra.
     423    // Mopra.  Updated position at epoch 2007/06/24 from Chris Phillips.
    349424    sprintf(telescope, "%-16.16s", "ATMOPRA");
    350     antPos[0] = -4682768.630;
    351     antPos[1] =  2802619.060;
    352     antPos[2] = -3291759.900;
     425    antPos[0] = -4682769.444; // ± 0.009
     426    antPos[1] =  2802618.963; // ± 0.006
     427    antPos[2] = -3291758.864; // ± 0.008
     428
    353429  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
    354430    // Hobart.
     
    357433    antPos[1] =  2522347.567;
    358434    antPos[2] = -4311562.569;
     435
    359436  } else if (strncmp(names_.sta, "CED", 3) == 0) {
    360     // Ceduna.
     437    // Ceduna.  Updated position at epoch 2007/06/24 from Chris Phillips.
    361438    sprintf(telescope, "%-16.16s", "CEDUNA");
    362     antPos[0] = -3749943.657;
    363     antPos[1] =  3909017.709;
    364     antPos[2] = -3367518.309;
     439    antPos[0] = -3753443.168; // ± 0.017
     440    antPos[1] =  3912709.794; // ± 0.017
     441    antPos[2] = -3348067.060; // ± 0.016
     442
    365443  } else if (strncmp(names_.sta, "tid", 3) == 0) {
    366444    // DSS.
     
    379457  obsType[j] = '\0';
    380458
     459  // Brightness unit.
     460  sprintf(bunit, "%-16.16s", names_.bunit);
     461  if (strcmp(bunit, "JY") == 0) {
     462    bunit[1] = 'y';
     463  } else if (strcmp(bunit, "JY/BEAM") == 0) {
     464    strcpy(bunit, "Jy/beam");
     465  }
     466
    381467  // Coordinate frames.
    382468  equinox = 2000.0f;
     
    386472  // Time at start of observation.
    387473  sprintf(datobs, "%-10.10s", names_.datobs);
    388   utc = ut;
     474  utc = cUTC;
    389475
    390476  // Spectral parameters.
     
    425511//--------------------------------------------------------- MBFITSreader::read
    426512
    427 // Read the next data record.
     513// Read the next data record (if you're feeling lucky).
    428514
    429515int MBFITSreader::read(
    430         PKSMBrecord &MBrec)
     516        MBrecord &MBrec)
    431517{
     518  const string methodName = "read()" ;
     519  LogIO os( LogOrigin( className, methodName, WHERE ) ) ;
     520
    432521  int beamNo = -1;
    433   int haveData, status;
    434   PKSMBrecord *iMBuff = 0x0;
     522  int haveData, pCode = 0, status;
     523  double raRate = 0.0, decRate = 0.0, paRate = 0.0;
     524  MBrecord *iMBuff = 0x0;
    435525
    436526  if (!cMBopen) {
    437     fprintf(stderr, "An MBFITS file has not been opened.\n");
     527    os << LogIO::SEVERE << "An MBFITS file has not been opened." << LogIO::POST ;
    438528    return 1;
    439529  }
    440530
    441   // Positions recorded in the input records do not coincide with the midpoint
    442   // of the integration and hence the input must be buffered so that true
    443   // positions may be interpolated.
     531  // Positions recorded in the input records usually do not coincide with the
     532  // midpoint of the integration and hence the input must be buffered so that
     533  // true positions may be interpolated.
    444534  //
    445535  // On the first call nBeamSel buffers of length nBin, are allocated and
     
    471561
    472562      // Read the next record.
     563      pCode = 0;
    473564      if ((status = rpget(0, cEOS)) == -1) {
    474565        // EOF.
     
    479570
    480571#ifdef PKSIO_DEBUG
    481         printf("End-of-file detected, flushing last scan.\n");
     572        os << LogIO::DEBUGGING << "\nEnd-of-file detected, flushing last cycle.\n" << LogIO::POST ;
    482573#endif
    483574
     
    507598          cXpolOff = new int[cNIF];
    508599
    509           int simulIF = 0;
    510600          int maxChan = 0;
    511601          int maxXpol = 0;
    512602
     603          cSimulIF = 0;
    513604          for (int iIF = 0; iIF < cNIF; iIF++) {
    514605            if (cIFs[iIF]) {
     
    536627
    537628              // Maximum number of selected IFs in any simultaneous set.
    538               simulIF = max(simulIF, cIFSel[iIF]+1);
     629              cSimulIF = max(cSimulIF, cIFSel[iIF]+1);
    539630
    540631              // Maximum memory required for any simultaneous set.
     
    563654
    564655          if (cNBin > 1 && cNBeamSel > 1) {
    565             fprintf(stderr, "Cannot handle binning mode for multiple "
    566                             "beams.\n");
     656            os << LogIO::SEVERE << "Cannot handle binning mode for multiple beams.\nSelect a single beam for input." << LogIO::POST ;
    567657            close();
    568658            return 1;
    569659          }
    570660
    571           // Allocate buffer data storage.
     661          // Allocate buffer data storage; the MBrecord constructor zeroes
     662          // class members such as cycleNo that are tested in the first pass
     663          // below.
    572664          int nBuff = cNBeamSel * cNBin;
    573           cBuffer = new PKSMBrecord[nBuff];
     665          cBuffer = new MBrecord[nBuff];
    574666
    575667          // Allocate memory for spectral arrays.
    576668          for (int ibuff = 0; ibuff < nBuff; ibuff++) {
    577             cBuffer[ibuff].setNIFs(simulIF);
     669            cBuffer[ibuff].setNIFs(cSimulIF);
    578670            cBuffer[ibuff].allocate(0, maxChan, maxXpol);
     671
     672            // Signal that this IF in this buffer has been flushed.
     673            for (int iIF = 0; iIF < cSimulIF; iIF++) {
     674              cBuffer[ibuff].IFno[iIF] = 0;
     675            }
    579676          }
    580677
     
    584681          cScanNo  = 1;
    585682          cCycleNo = 0;
    586           cUTC = 0.0;
    587           cStaleness = new int[cNBeamSel];
    588           for (int iBeamSel = 0; iBeamSel < cNBeamSel; iBeamSel++) {
    589             cStaleness[iBeamSel] = 0;
    590           }
     683          cPrevUTC = -1.0;
    591684        }
    592685
     
    595688          cScanNo++;
    596689          cCycleNo = 0;
    597           cUTC = 0.0;
    598         }
    599 
    600         // Apply beam selection.
    601         beamNo = int(baseline / 256.0);
     690          cPrevUTC = -1.0;
     691        }
     692
     693        // Apply beam and IF selection before the change-of-day test to allow
     694        // a single selected beam and IF to be handled in binning-mode.
     695        beamNo = int(cBaseline / 256.0);
     696        if (beamNo == 1) {
     697          // Store the position of beam 1 for grid convergence corrections.
     698          cRA0  = cU;
     699          cDec0 = cV;
     700        }
    602701        iBeamSel = cBeamSel[beamNo-1];
    603702        if (iBeamSel < 0) continue;
    604703
    605704        // Sanity check (mainly for MOPS).
    606         if (if_no > cNIF) continue;
    607 
    608         // Apply IF selection.
    609         iIFSel = cIFSel[if_no - 1];
     705        if (cIFno > cNIF) continue;
     706
     707        // Apply IF selection; iIFSel == 0 for the first selected IF, == 1
     708        // for the second, etc.
     709        iIFSel = cIFSel[cIFno - 1];
    610710        if (iIFSel < 0) continue;
    611711
    612         sprintf(cDateObs, "%-10.10s", names_.datobs);
    613 
    614         // Change-of-day; note that the ut variable from RPFITS.h is global
    615         // and will be preserved between calls to this function.
    616         if (ut < cUTC - 85800.0) {
    617           ut += 86400.0;
    618         }
    619 
    620         // New integration cycle?
    621         if (ut > cUTC) {
    622           cCycleNo++;
    623           cUTC = ut + 0.0001;
    624         }
    625712
    626713        if (cNBin > 1) {
    627714          // Binning mode: correct the time.
    628           ut += param_.intbase * (bin - (cNBin + 1)/2.0);
    629         }
     715          cUTC += param_.intbase * (cBin - (cNBin + 1)/2.0);
     716        }
     717
     718        // Check for change-of-day.
     719        double cod = 0.0;
     720        if ((cUTC + 86400.0) < (cPrevUTC + 600.0)) {
     721          // cUTC should continue to increase past 86400 during a single scan.
     722          // However, if the RPFITS file contains multiple scans that straddle
     723          // midnight then cUTC can jump backwards from the end of one scan to
     724          // the start of the next.
     725#ifdef PKSIO_DEBUG
     726          char buf[256] ;
     727          sprintf(buf, "Change-of-day on cUTC: %.1f -> %.1f\n", cPrevUTC, cUTC);
     728          os << LogIO::DEBUGGING << buf << LogIO::POST ;
     729#endif
     730          // Can't change the recorded value of cUTC directly (without also
     731          // changing dateobs) so change-of-day must be recorded separately as
     732          // an offset to be applied when comparing integration timestamps.
     733          cod = 86400.0;
     734
     735        }
     736
     737        if ((cUTC+cod) < cPrevUTC - 1.0) {
     738          if (cBin == 1 && iIFSel) {
     739            // Multiple-IF, binning-mode data is only partially time ordered.
     740#ifdef PKSIO_DEBUG
     741            fprintf(stderr, "New IF in multiple-IF, binning-mode data.\n");
     742#endif
     743            cCycleNo -= cNBin;
     744            cPrevUTC = -1.0;
     745
     746          } else {
     747            // All other data should be fully time ordered.
     748            sprintf(cMsg,
     749              "Cycle %d:%03d-%03d, UTC went backwards from\n"
     750              "%.1f to %.1f!  Incrementing day number,\n"
     751              "positions may be unreliable.", cScanNo, cCycleNo,
     752              cCycleNo+1, cPrevUTC, cUTC);
     753            //logMsg(cMsg);
     754            os << LogIO::WARN << cMsg << LogIO::POST ;
     755            cUTC += 86400.0;
     756          }
     757        }
     758
     759        // New integration cycle?
     760        if ((cUTC+cod) > cPrevUTC) {
     761          cCycleNo++;
     762          cPrevUTC = cUTC + 0.0001;
     763        }
     764
     765        sprintf(cDateObs, "%-10.10s", names_.datobs);
     766        cDateObs[10] = '\0';
    630767
    631768        // Compute buffer number.
    632769        iMBuff = cBuffer + iBeamSel;
    633         if (cNBin > 1) iMBuff += cNBeamSel*(bin-1);
     770        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
    634771
    635772        if (cCycleNo < iMBuff->cycleNo) {
     
    640777
    641778        // Begin flush cycle?
    642         if (cEOS || (iMBuff->nIF && ut > iMBuff->utc + 0.0001)) {
     779        if (cEOS || (iMBuff->nIF && (cUTC+cod) > (iMBuff->utc+0.0001))) {
    643780          cFlushing = 1;
    644781          cFlushBin = 0;
     
    647784
    648785#ifdef PKSIO_DEBUG
    649         printf(" In:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, if_no);
    650         if (cEOS) printf("Start of new scan, flushing previous scan.\n");
     786        char rel = '=';
     787        double dt = utcDiff(cUTC, cW);
     788        if (dt < 0.0) {
     789          rel = '<';
     790        } else if (dt > 0.0) {
     791          rel = '>';
     792        }
     793
     794        sprintf(buf, "\n In:%4d%4d%3d%3d  %.3f %c %.3f (%+.3fs) - "
     795          "%sflushing\n", cScanNo, cCycleNo, beamNo, cIFno, cUTC, rel, cW, dt,
     796          cFlushing ? "" : "not ");
     797        os << LogIO::DEBUGGING << buf << LogIO::POST ;
     798        if (cEOS) {
     799          sprintf(buf, "Start of new scan, flushing previous scan.\n");
     800          os << LogIO::DEBUGGING << buf << LogIO::POST ;
     801        }
    651802#endif
    652803      }
     
    663814          iMBuff = cBuffer + iBeamSel + cNBeamSel*cFlushBin;
    664815
    665           // iMBuff->nIF is set to zero (below) to signal that all IFs in
    666           // an integration have been flushed.
     816          // iMBuff->nIF is decremented (below) and if zero signals that all
     817          // IFs in an integration have been flushed.
    667818          if (iMBuff->nIF) {
    668819            if (cycleNo == 0 || iMBuff->cycleNo < cycleNo) {
     
    677828          break;
    678829        }
     830
     831        // Start with the first IF in the next bin.
     832        cFlushIF = 0;
    679833      }
    680834
     
    684838
    685839        // Find the IF to flush.
    686         for (; cFlushIF < iMBuff->nIF; cFlushIF++) {
     840        for (; cFlushIF < cSimulIF; cFlushIF++) {
    687841          if (iMBuff->IFno[cFlushIF]) break;
    688842        }
     
    696850
    697851        // The last record read must have been the first of a new cycle.
    698         beamNo = int(baseline / 256.0);
     852        beamNo = int(cBaseline / 256.0);
    699853        iBeamSel = cBeamSel[beamNo-1];
    700854
    701855        // Compute buffer number.
    702856        iMBuff = cBuffer + iBeamSel;
    703         if (cNBin > 1) iMBuff += cNBeamSel*(bin-1);
     857        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
    704858      }
    705859    }
    706860
    707861
    708     if (cFlushing && cFlushBin == 0 && cFlushIF == 0 && cInterp) {
    709       // Interpolate the beam position at the start of the flush cycle.
     862    if (cInterp && cFlushing == 1) {
     863      // Start of flush cycle, interpolate the beam position.
     864      //
     865      // The position is measured by the control system at a time returned by
     866      // RPFITSIN as the 'w' visibility coordinate.  The ra and dec, returned
     867      // as the 'u' and 'v' visibility coordinates, must be interpolated to
     868      // the integration time which RPFITSIN returns as 'cUTC', this usually
     869      // being a second or two later.  The interpolation method used here is
     870      // based on the scan rate.
     871      //
     872      // "This" RA, Dec, and UTC refers to the position currently stored in
     873      // the buffer marked for output (iMBuff).  This position is interpolated
     874      // to the midpoint of that integration using either
     875      //   a) the rate currently sitting in iMBuff, which was computed from
     876      //      the previous integration, otherwise
     877      //   b) from the position recorded in the "next" integration which is
     878      //      currently sitting in the RPFITS commons,
     879      // so that the position timestamps straddle the midpoint of the
     880      // integration and is thereby interpolated rather than extrapolated.
     881      //
     882      // At the end of a scan, or if the next position has not been updated
     883      // or its timestamp does not advance sufficiently, the most recent
     884      // determination of the scan rate will be used for extrapolation which
     885      // is quantified by the "rate age" measured in seconds beyond the
     886      // interval defined by the position timestamps.
     887
     888      // At this point, iMBuff contains cU, cV, cW, parAngle and focusRot
     889      // stored from the previous call to rpget() for this beam (i.e. "this"),
     890      // and also raRate, decRate and paRate computed from that integration
     891      // and the previous one.
     892      double thisRA  = iMBuff->ra;
     893      double thisDec = iMBuff->dec;
     894      double thisUTC = cPosUTC[iBeamSel];
     895      double thisPA  = iMBuff->parAngle + iMBuff->focusRot;
     896
    710897#ifdef PKSIO_DEBUG
    711       printf("Doing position interpolation for beam %d.\n", iMBuff->beamNo);
     898      sprintf(buf, "This (%d) ra, dec, UTC: %9.4f %9.4f %10.3f %9.4f\n",
     899        iMBuff->cycleNo, thisRA*R2D, thisDec*R2D, thisUTC, thisPA*R2D);
     900      os << LogIO::DEBUGGING << buf << LogIO::POST ;
    712901#endif
    713902
    714       double prevRA  = iMBuff->ra;
    715       double prevDec = iMBuff->dec;
    716       double prevUTC = cPosUTC[iBeamSel];
    717 
    718       if (!cEOF && !cEOS) {
    719         // The position is measured by the control system at a time returned
    720         // by RPFITSIN as the 'w' visibility coordinate.  The ra and dec,
    721         // returned as the 'u' and 'v' visibility coordinates, must be
    722         // interpolated to the integration time which RPFITSIN returns as
    723         // 'ut', this usually being a second or two later.
    724         //
    725         // Note that the time recorded as the 'w' visibility coordinate
    726         // cycles through 86400 back to 0 at midnight, whereas that in 'ut'
    727         // continues to increase past 86400.
    728 
    729         double thisRA  = u;
    730         double thisDec = v;
    731         double thisUTC = w;
    732 
    733         if (thisUTC < prevUTC) {
    734           // Must have cycled through midnight.
    735           thisUTC += 86400.0;
    736         }
    737 
    738         // Guard against RA cycling through 24h in either direction.
    739         if (fabs(thisRA - prevRA) > PI) {
    740           if (thisRA < prevRA) {
    741             thisRA += TWOPI;
     903      if (cEOF || cEOS) {
     904        // Use rates from the last cycle.
     905        raRate  = iMBuff->raRate;
     906        decRate = iMBuff->decRate;
     907        paRate  = iMBuff->paRate;
     908
     909      } else {
     910        if (cW == thisUTC) {
     911          // The control system at Mopra typically does not update the
     912          // positions between successive integration cycles at the end of a
     913          // scan (nor are they flagged).  In this case we use the previously
     914          // computed rates, even if from the previous scan since these are
     915          // likely to be a better guess than anything else.
     916          raRate  = iMBuff->raRate;
     917          decRate = iMBuff->decRate;
     918          paRate  = iMBuff->paRate;
     919
     920          if (cU == thisRA && cV == thisDec) {
     921            // Position and timestamp unchanged.
     922            pCode = 1;
     923
     924          } else if (fabs(cU-thisRA) < 0.0001 && fabs(cV-thisDec) < 0.0001) {
     925            // Allow small rounding errors (seen infrequently).
     926            pCode = 1;
     927
    742928          } else {
    743             thisRA -= TWOPI;
     929            // (cU,cV) are probably rubbish (not yet seen in practice).
     930            pCode = 2;
     931            cU = thisRA;
     932            cV = thisDec;
    744933          }
    745         }
    746 
    747         // The control system at Mopra typically does not update the
    748         // positions between successive integration cycles at the end of a
    749         // scan (nor are they flagged).  In this case we use the previously
    750         // computed rates, even if from the previous scan since these are
    751         // likely to be a better guess than anything else.
    752 
    753         double dUTC = thisUTC - prevUTC;
    754 
    755         // Scan rate for this beam.
    756         if (dUTC > 0.0) {
    757           iMBuff->raRate  = (thisRA  - prevRA)  / dUTC;
    758           iMBuff->decRate = (thisDec - prevDec) / dUTC;
    759 
    760           if (cInterp == 2) {
    761             // Use the same interpolation scheme as the original pksmbfits
    762             // client.  This incorrectly assumed that (thisUTC - prevUTC) is
    763             // equal to the integration time and interpolated by computing a
    764             // weighted sum of the positions before and after the required
    765             // time.
    766 
    767             double utc = iMBuff->utc;
    768             if (utc - prevUTC > 100.0) {
    769               // Must have cycled through midnight.
    770               utc -= 86400.0;
     934
     935#ifdef PKSIO_DEBUG
     936          sprintf(buf, "Next (%d) ra, dec, UTC: %9.4f %9.4f %10.3f "
     937            "(0.000s)\n", cCycleNo, cU*R2D, cV*R2D, cW);
     938          os << LogIO::DEBUGGING << buf << LogIO::POST ;
     939#endif
     940
     941        } else {
     942          double nextRA  = cU;
     943          double nextDec = cV;
     944
     945          // Check and, if necessary, repair the position timestamp,
     946          // remembering that pCode refers to the NEXT cycle.
     947          pCode = fixw(cDateObs, cCycleNo, beamNo, cAvRate, thisRA, thisDec,
     948                       thisUTC, nextRA, nextDec, cW);
     949          if (pCode > 0) pCode += 3;
     950          double nextUTC = cW;
     951
     952#ifdef PKSIO_DEBUG
     953          sprintf(buf, "Next (%d) ra, dec, UTC: %9.4f %9.4f %10.3f "
     954            "(%+.3fs)\n", cCycleNo, nextRA*R2D, nextDec*R2D, nextUTC,
     955            utcDiff(nextUTC, thisUTC));
     956          os << LogIO::DEBUGGING << buf << LogIO::POST ;
     957#endif
     958
     959          // Compute the scan rate for this beam.
     960          double dUTC = utcDiff(nextUTC, thisUTC);
     961          if ((0.0 < dUTC) && (dUTC < 600.0)) {
     962            scanRate(cRA0, cDec0, thisRA, thisDec, nextRA, nextDec, dUTC,
     963                     raRate, decRate);
     964
     965            // Update the mean scan rate.
     966            cAvRate[0] = (cAvRate[0]*cNRate +  raRate) / (cNRate + 1);
     967            cAvRate[1] = (cAvRate[1]*cNRate + decRate) / (cNRate + 1);
     968            cNRate++;
     969
     970            // Rate of change of position angle.
     971            if (sc_.sc_ant <= anten_.nant) {
     972              paRate = 0.0;
     973            } else {
     974              int iOff = sc_.sc_q * (sc_.sc_ant - 1) - 1;
     975              double nextPA = sc_.sc_cal[iOff + 4] + sc_.sc_cal[iOff + 7];
     976              double paDiff = nextPA - thisPA;
     977              if (paDiff > PI) {
     978                paDiff -= TWOPI;
     979              } else if (paDiff < -PI) {
     980                paDiff += TWOPI;
     981              }
     982              paRate = paDiff / dUTC;
    771983            }
    772984
    773             double tw1 = 1.0 - (utc - prevUTC) / iMBuff->exposure;
    774             double tw2 = 1.0 - (thisUTC - utc) / iMBuff->exposure;
    775             double gamma = (tw2 / (tw1 + tw2)) * dUTC / (utc - prevUTC);
    776 
    777             iMBuff->raRate  *= gamma;
    778             iMBuff->decRate *= gamma;
    779           }
    780 
    781           cStaleness[iBeamSel] = 0;
    782 
    783         } else {
    784           // Issue warnings.
    785           int nch = 0;
    786           fprintf(stderr, "WARNING, scan %d,%n cycle %d: Position ",
    787             iMBuff->scanNo, &nch, iMBuff->cycleNo);
    788 
    789           if (dUTC < 0.0) {
    790             fprintf(stderr, "timestamp went backwards!\n");
     985            if (cInterp == 2) {
     986              // Use the same interpolation scheme as the original pksmbfits
     987              // client.  This incorrectly assumed that (nextUTC - thisUTC) is
     988              // equal to the integration time and interpolated by computing a
     989              // weighted sum of the positions before and after the required
     990              // time.
     991
     992              double utc = iMBuff->utc;
     993              double tw1 = 1.0 - utcDiff(utc, thisUTC) / iMBuff->exposure;
     994              double tw2 = 1.0 - utcDiff(nextUTC, utc) / iMBuff->exposure;
     995              double gamma = (tw2 / (tw1 + tw2)) * dUTC / (utc - thisUTC);
     996
     997              // Guard against RA cycling through 24h in either direction.
     998              if (fabs(nextRA - thisRA) > PI) {
     999                if (nextRA < thisRA) {
     1000                  nextRA += TWOPI;
     1001                } else {
     1002                  nextRA -= TWOPI;
     1003                }
     1004              }
     1005
     1006              raRate  = gamma * (nextRA  - thisRA)  / dUTC;
     1007              decRate = gamma * (nextDec - thisDec) / dUTC;
     1008            }
     1009
    7911010          } else {
    792             if (thisRA != prevRA || thisDec != prevDec) {
    793               fprintf(stderr, "changed but timestamp unchanged!\n");
     1011            if (cCycleNo == 2 && fabs(utcDiff(cUTC,cW)) < 600.0) {
     1012              // thisUTC (i.e. cW for the first cycle) is rubbish, and
     1013              // probably the position as well (extremely rare in practice,
     1014              // e.g. 97-12-19_1029_235708-18_586e.hpf which actually has the
     1015              // t/1000 scaling bug in the first cycle).
     1016              iMBuff->pCode = 3;
     1017              thisRA  = cU;
     1018              thisDec = cV;
     1019              thisUTC = cW;
     1020              raRate  = 0.0;
     1021              decRate = 0.0;
     1022              paRate  = 0.0;
     1023
    7941024            } else {
    795               fprintf(stderr, "and timestamp unchanged!\n");
     1025              // cW is rubbish and probably (cU,cV), and possibly the
     1026              // parallactic angle and everything else as well (rarely seen
     1027              // in practice, e.g. 97-12-09_0743_235707-58_327c.hpf and
     1028              // 97-09-01_0034_123717-42_242b.hpf, the latter with bad
     1029              // parallactic angle).
     1030              pCode = 3;
     1031              cU = thisRA;
     1032              cV = thisDec;
     1033              cW = thisUTC;
     1034              raRate  = iMBuff->raRate;
     1035              decRate = iMBuff->decRate;
     1036              paRate  = iMBuff->paRate;
    7961037            }
    7971038          }
    798 
    799           cStaleness[iBeamSel]++;
    800           fprintf(stderr, "%-*s Using stale scan rate, staleness = %d "
    801             "cycle%s.\n", nch, "WARNING,", cStaleness[iBeamSel],
    802             (cStaleness[iBeamSel] == 1) ? "" : "s");
    803 
    804           if (thisRA != prevRA || thisDec != prevDec) {
    805             if (iMBuff->raRate == 0.0 && iMBuff->decRate == 0.0) {
    806               fprintf(stderr, "%-*s But the previous rate was zero!  "
    807                 "Position will be inaccurate.\n", nch, "WARNING,");
     1039        }
     1040      }
     1041
     1042
     1043      // Choose the closest rate determination.
     1044      if (cCycleNo == 1) {
     1045        // Scan containing a single integration.
     1046        iMBuff->raRate  = 0.0;
     1047        iMBuff->decRate = 0.0;
     1048        iMBuff->paRate  = 0.0;
     1049
     1050      } else {
     1051        double dUTC = iMBuff->utc - cPosUTC[iBeamSel];
     1052
     1053        if (dUTC >= 0.0) {
     1054          // In HIPASS/ZOA, the position timestamp, which should always occur
     1055          // on the whole second, normally precedes an integration midpoint
     1056          // falling on the half-second.  Consequently, positive ages are
     1057          // always half-integral.
     1058          dUTC = utcDiff(iMBuff->utc, cW);
     1059          if (dUTC > 0.0) {
     1060            iMBuff->rateAge = dUTC;
     1061          } else {
     1062            iMBuff->rateAge = 0.0f;
     1063          }
     1064
     1065          iMBuff->raRate  =  raRate;
     1066          iMBuff->decRate = decRate;
     1067          iMBuff->paRate  =  paRate;
     1068
     1069        } else {
     1070          // In HIPASS/ZOA, negative ages occur when the integration midpoint,
     1071          // occurring on the whole second, precedes the position timestamp.
     1072          // Thus negative ages are always an integral number of seconds.
     1073          // They have only been seen to occur sporadically in the period
     1074          // 1999/05/31 to 1999/11/01, e.g. 1999-07-26_1821_005410-74_007c.hpf
     1075          //
     1076          // In recent (2008/10/07) Mopra data, small negative ages (~10ms,
     1077          // occasionally up to ~300ms) seem to be the norm, with both the
     1078          // position timestamp and integration midpoint falling close to but
     1079          // not on the integral second.
     1080          if (cCycleNo == 2) {
     1081            // We have to start with something!
     1082            iMBuff->rateAge = dUTC;
     1083
     1084          } else {
     1085            // Although we did not record the relevant position timestamp
     1086            // explicitly, it can easily be deduced.
     1087            double w = iMBuff->utc - utcDiff(cUTC, iMBuff->utc) -
     1088                       iMBuff->rateAge;
     1089            dUTC = utcDiff(iMBuff->utc, w);
     1090
     1091            if (dUTC > 0.0) {
     1092              iMBuff->rateAge = 0.0f;
     1093            } else {
     1094              iMBuff->rateAge = dUTC;
    8081095            }
    8091096          }
    810         }
    811       }
     1097
     1098          iMBuff->raRate  =  raRate;
     1099          iMBuff->decRate = decRate;
     1100          iMBuff->paRate  =  paRate;
     1101        }
     1102      }
     1103
     1104#ifdef PKSIO_DEBUG
     1105      double avRate = sqrt(cAvRate[0]*cAvRate[0] + cAvRate[1]*cAvRate[1]);
     1106      sprintf(buf, "RA, Dec, Av & PA rates: %8.4f %8.4f %8.4f %8.4f "
     1107        "pCode %d\n", raRate*R2D, decRate*R2D, avRate*R2D, paRate*R2D, pCode);
     1108      os << LogIO::DEBUGGING << buf << LogIO::POST ;
     1109#endif
     1110
    8121111
    8131112      // Compute the position of this beam for all bins.
     
    8171116        cBuffer[jbuff].raRate  = iMBuff->raRate;
    8181117        cBuffer[jbuff].decRate = iMBuff->decRate;
    819 
    820         double dutc = cBuffer[jbuff].utc - prevUTC;
    821         if (dutc > 100.0) {
     1118        cBuffer[jbuff].paRate  = iMBuff->paRate;
     1119
     1120        double dUTC = utcDiff(cBuffer[jbuff].utc, thisUTC);
     1121        if (dUTC > 100.0) {
    8221122          // Must have cycled through midnight.
    823           dutc -= 86400.0;
    824         }
    825 
    826         cBuffer[jbuff].ra  = prevRA  + cBuffer[jbuff].raRate  * dutc;
    827         cBuffer[jbuff].dec = prevDec + cBuffer[jbuff].decRate * dutc;
    828         if (cBuffer[jbuff].ra < 0.0) {
    829           cBuffer[jbuff].ra += TWOPI;
    830         } else if (cBuffer[jbuff].ra > TWOPI) {
    831           cBuffer[jbuff].ra -= TWOPI;
    832         }
    833       }
     1123          dUTC -= 86400.0;
     1124        }
     1125
     1126        applyRate(cRA0, cDec0, thisRA, thisDec,
     1127          cBuffer[jbuff].raRate, cBuffer[jbuff].decRate, dUTC,
     1128          cBuffer[jbuff].ra, cBuffer[jbuff].dec);
     1129
     1130#ifdef PKSIO_DEBUG
     1131        sprintf(buf, "Intp (%d) ra, dec, UTC: %9.4f %9.4f %10.3f (pCode, "
     1132          "age: %d %.1fs)\n", iMBuff->cycleNo, cBuffer[jbuff].ra*R2D,
     1133          cBuffer[jbuff].dec*R2D, cBuffer[jbuff].utc, iMBuff->pCode,
     1134          iMBuff->rateAge);
     1135        os << LogIO::DEBUGGING << buf << LogIO::POST ;
     1136#endif
     1137      }
     1138
     1139      cFlushing = 2;
    8341140    }
    8351141
     
    8411147
    8421148#ifdef PKSIO_DEBUG
    843       printf("Out:%4d%4d%3d%3d\n", MBrec.scanNo, MBrec.cycleNo, MBrec.beamNo,
    844         MBrec.IFno[0]);
     1149      sprintf(buf, "Out:%4d%4d%3d%3d\n", MBrec.scanNo, MBrec.cycleNo,
     1150        MBrec.beamNo, MBrec.IFno[0]);
     1151      os << LogIO::DEBUGGING << buf << LogIO::POST ;
    8451152#endif
    8461153
     
    8481155      iMBuff->IFno[cFlushIF] = 0;
    8491156
    850       if (cFlushIF == iMBuff->nIF - 1) {
    851         // Signal that all IFs in this buffer location have been flushed.
    852         iMBuff->nIF = 0;
     1157      iMBuff->nIF--;
     1158      if (iMBuff->nIF == 0) {
     1159        // All IFs in this buffer location have been flushed.  Stop cEOS
     1160        // being set when the next integration is read.
     1161        iMBuff->cycleNo = 0;
     1162
    8531163      } else {
    8541164        // Carry on flushing the other IFs.
     
    8591169      if (cFlushBin == cNBin - 1) {
    8601170        if (cEOS || cEOF) {
    861           // Stop cEOS being set when the next integration is read.
    862           iMBuff->cycleNo = 0;
    863 
    8641171          // Carry on flushing other buffers.
    8651172          cFlushIF = 0;
     
    8691176        cFlushing = 0;
    8701177
    871         beamNo = int(baseline / 256.0);
     1178        beamNo = int(cBaseline / 256.0);
    8721179        iBeamSel = cBeamSel[beamNo-1];
    8731180
    8741181        // Compute buffer number.
    8751182        iMBuff = cBuffer + iBeamSel;
    876         if (cNBin > 1) iMBuff += cNBeamSel*(bin-1);
     1183        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
    8771184      }
    8781185    }
     
    8801187    if (!cFlushing) {
    8811188      // Buffer this MBrec.
    882       if (cCycleNo == 1 && iMBuff->IFno[0]) {
     1189      if ((cScanNo > iMBuff->scanNo) && iMBuff->IFno[0]) {
    8831190        // Sanity check on the number of IFs in the new scan.
    8841191        if (if_.n_if != cNIF) {
    885           fprintf(stderr, "WARNING, scan %d has %d IFs instead of %d, "
    886             "continuing.\n", cScanNo, if_.n_if, cNIF);
    887         }
    888       }
    889 
    890       iMBuff->scanNo  = cScanNo;
    891       iMBuff->cycleNo = cCycleNo;
    892 
    893       // Times.
    894       strncpy(iMBuff->datobs, cDateObs, 10);
    895       iMBuff->utc = ut;
    896       iMBuff->exposure = param_.intbase;
    897 
    898       // Source identification.
    899       sprintf(iMBuff->srcName, "%-16.16s",
    900               names_.su_name + (sourceno-1)*16);
    901       iMBuff->srcRA  = doubles_.su_ra[sourceno-1];
    902       iMBuff->srcDec = doubles_.su_dec[sourceno-1];
    903 
    904       // Rest frequency of the line of interest.
    905       iMBuff->restFreq = doubles_.rfreq;
    906       if (strncmp(names_.instrument, "ATPKSMB", 7) == 0) {
    907         // Fix the HI rest frequency recorded for Parkes multibeam data.
    908         double reffreq  = doubles_.freq;
    909         double restfreq = doubles_.rfreq;
    910         if ((restfreq == 0.0 || fabs(restfreq - reffreq) == 0.0) &&
    911              fabs(reffreq - 1420.40575e6) < 100.0) {
    912           iMBuff->restFreq = 1420.40575e6;
    913         }
    914       }
    915 
    916       // Observation type.
    917       int j;
    918       for (j = 0; j < 15; j++) {
    919         iMBuff->obsType[j] = names_.card[11+j];
    920         if (iMBuff->obsType[j] == '\'') break;
    921       }
    922       iMBuff->obsType[j] = '\0';
    923 
    924       // Beam-dependent parameters.
    925       iMBuff->beamNo = beamNo;
    926 
    927       // Beam position at the specified time.
    928       if (cTid) {
    929         // Tidbinbilla data.
    930         iMBuff->ra  = doubles_.su_ra[sourceno-1];
    931         iMBuff->dec = doubles_.su_dec[sourceno-1];
    932       } else {
    933         iMBuff->ra  = u;
    934         iMBuff->dec = v;
    935       }
    936       cPosUTC[iBeamSel] = w;
     1192          sprintf(cMsg, "Scan %d has %d IFs instead of %d, "
     1193            "continuing.", cScanNo, if_.n_if, cNIF);
     1194          os << LogIO::WARN << cMsg << LogIO::POST ;
     1195        }
     1196      }
     1197
     1198      // Sanity check on incomplete integrations within a scan.
     1199      if (iMBuff->nIF && (iMBuff->cycleNo != cCycleNo)) {
     1200        // Force the incomplete integration to be flushed before proceeding.
     1201        cFlushing = 1;
     1202        continue;
     1203      }
     1204
     1205#ifdef PKSIO_DEBUG
     1206      sprintf(buf, "Buf:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, cIFno);
     1207      os << LogIO::DEBUGGING << buf << LogIO::POST ;
     1208#endif
     1209
     1210      // Store IF-independent parameters only for the first IF of a new cycle,
     1211      // particularly because this is the only one for which the scan rates
     1212      // are computed above.
     1213      int firstIF = (iMBuff->nIF == 0);
     1214      if (firstIF) {
     1215        iMBuff->scanNo  = cScanNo;
     1216        iMBuff->cycleNo = cCycleNo;
     1217
     1218        // Times.
     1219        strcpy(iMBuff->datobs, cDateObs);
     1220        iMBuff->utc = cUTC;
     1221        iMBuff->exposure = param_.intbase;
     1222
     1223        // Source identification.
     1224        sprintf(iMBuff->srcName, "%-16.16s",
     1225                names_.su_name + (cSrcNo-1)*16);
     1226        iMBuff->srcName[16] = '\0';
     1227        iMBuff->srcRA  = doubles_.su_ra[cSrcNo-1];
     1228        iMBuff->srcDec = doubles_.su_dec[cSrcNo-1];
     1229
     1230        // Rest frequency of the line of interest.
     1231        iMBuff->restFreq = doubles_.rfreq;
     1232        if (strncmp(names_.instrument, "ATPKSMB", 7) == 0) {
     1233          // Fix the HI rest frequency recorded for Parkes multibeam data.
     1234          double reffreq  = doubles_.freq;
     1235          double restfreq = doubles_.rfreq;
     1236          if ((restfreq == 0.0 || fabs(restfreq - reffreq) == 0.0) &&
     1237               fabs(reffreq - 1420.405752e6) < 100.0) {
     1238            iMBuff->restFreq = 1420.405752e6;
     1239          }
     1240        }
     1241
     1242        // Observation type.
     1243        int j;
     1244        for (j = 0; j < 15; j++) {
     1245          iMBuff->obsType[j] = names_.card[11+j];
     1246          if (iMBuff->obsType[j] == '\'') break;
     1247        }
     1248        iMBuff->obsType[j] = '\0';
     1249
     1250        // Beam-dependent parameters.
     1251        iMBuff->beamNo = beamNo;
     1252
     1253        // Beam position at the specified time.
     1254        if (cSUpos) {
     1255          // Non-ATNF data that does not store the position in (u,v,w).
     1256          iMBuff->ra  = doubles_.su_ra[cSrcNo-1];
     1257          iMBuff->dec = doubles_.su_dec[cSrcNo-1];
     1258        } else {
     1259          iMBuff->ra  = cU;
     1260          iMBuff->dec = cV;
     1261        }
     1262        cPosUTC[iBeamSel] = cW;
     1263        iMBuff->pCode = pCode;
     1264
     1265        // Store rates for next time.
     1266        iMBuff->raRate  =  raRate;
     1267        iMBuff->decRate = decRate;
     1268        iMBuff->paRate  =  paRate;
     1269      }
    9371270
    9381271      // IF-dependent parameters.
    939       int iIF = if_no - 1;
     1272      int iIF = cIFno - 1;
    9401273      int startChan = cStartChan[iIF];
    9411274      int endChan   = cEndChan[iIF];
     
    9451278
    9461279      iIFSel = cIFSel[iIF];
    947       iMBuff->nIF++;
    948       iMBuff->IFno[iIFSel]  = if_no;
     1280      if (iMBuff->IFno[iIFSel] == 0) {
     1281        iMBuff->nIF++;
     1282        iMBuff->IFno[iIFSel] = cIFno;
     1283      } else {
     1284        // Integration cycle written to the output file twice (the only known
     1285        // example is 1999-05-22_1914_000-031805_03v.hpf).
     1286        sprintf(cMsg, "Integration cycle %d:%d, beam %2d, \n"
     1287                      "IF %d was duplicated.", cScanNo, cCycleNo-1,
     1288                      beamNo, cIFno);
     1289        os << LogIO::WARN << cMsg << LogIO::POST ;
     1290      }
    9491291      iMBuff->nChan[iIFSel] = nChan;
    9501292      iMBuff->nPol[iIFSel]  = cNPol[iIF];
     
    10051347
    10061348      // The baseline flag may be set independently.
    1007       if (rpflag == 0) rpflag = flag;
     1349      if (rpflag == 0) rpflag = cFlag;
    10081350
    10091351      // Copy and scale data.
     
    10461388
    10471389
    1048       // Parallactic angle.
    1049       iMBuff->parAngle = sc_.sc_cal[scq*iBeam + 11];
    1050 
    10511390      // Calibration factor applied to the data by the correlator.
    10521391      if (scq > 14) {
     
    10591398      }
    10601399
    1061       if (sc_.sc_ant <= anten_.nant) {
    1062         // No extra syscal information present.
    1063         iMBuff->extraSysCal = 0;
    1064         iMBuff->azimuth   = 0.0f;
    1065         iMBuff->elevation = 0.0f;
    1066         iMBuff->parAngle  = 0.0f;
    1067         iMBuff->focusAxi  = 0.0f;
    1068         iMBuff->focusTan  = 0.0f;
    1069         iMBuff->focusRot  = 0.0f;
    1070         iMBuff->temp      = 0.0f;
    1071         iMBuff->pressure  = 0.0f;
    1072         iMBuff->humidity  = 0.0f;
    1073         iMBuff->windSpeed = 0.0f;
    1074         iMBuff->windAz    = 0.0f;
    1075         strcpy(iMBuff->tcalTime, "                ");
    1076         iMBuff->refBeam = 0;
    1077 
    1078       } else {
    1079         // Additional information for Parkes Multibeam data.
    1080         int iOff = scq*(sc_.sc_ant - 1) - 1;
    1081         iMBuff->extraSysCal = 1;
    1082         iMBuff->azimuth   = sc_.sc_cal[iOff + 2];
    1083         iMBuff->elevation = sc_.sc_cal[iOff + 3];
    1084         iMBuff->parAngle  = sc_.sc_cal[iOff + 4];
    1085         iMBuff->focusAxi  = sc_.sc_cal[iOff + 5] * 1e-3;
    1086         iMBuff->focusTan  = sc_.sc_cal[iOff + 6] * 1e-3;
    1087         iMBuff->focusRot  = sc_.sc_cal[iOff + 7];
    1088         iMBuff->temp      = sc_.sc_cal[iOff + 8];
    1089         iMBuff->pressure  = sc_.sc_cal[iOff + 9];
    1090         iMBuff->humidity  = sc_.sc_cal[iOff + 10];
    1091         iMBuff->windSpeed = sc_.sc_cal[iOff + 11];
    1092         iMBuff->windAz    = sc_.sc_cal[iOff + 12];
    1093 
    1094         char *tcalTime = iMBuff->tcalTime;
    1095         sprintf(tcalTime, "%-16.16s", (char *)(&sc_.sc_cal[iOff+13]));
     1400      if (firstIF) {
     1401        if (sc_.sc_ant <= anten_.nant) {
     1402          // No extra syscal information present.
     1403          iMBuff->extraSysCal = 0;
     1404          iMBuff->azimuth   = 0.0f;
     1405          iMBuff->elevation = 0.0f;
     1406          iMBuff->parAngle  = 0.0f;
     1407          iMBuff->focusAxi  = 0.0f;
     1408          iMBuff->focusTan  = 0.0f;
     1409          iMBuff->focusRot  = 0.0f;
     1410          iMBuff->temp      = 0.0f;
     1411          iMBuff->pressure  = 0.0f;
     1412          iMBuff->humidity  = 0.0f;
     1413          iMBuff->windSpeed = 0.0f;
     1414          iMBuff->windAz    = 0.0f;
     1415          strcpy(iMBuff->tcalTime, "                ");
     1416          iMBuff->refBeam = 0;
     1417
     1418        } else {
     1419          // Additional information for Parkes Multibeam data.
     1420          int iOff = scq*(sc_.sc_ant - 1) - 1;
     1421          iMBuff->extraSysCal = 1;
     1422
     1423          iMBuff->azimuth   = sc_.sc_cal[iOff + 2];
     1424          iMBuff->elevation = sc_.sc_cal[iOff + 3];
     1425          iMBuff->parAngle  = sc_.sc_cal[iOff + 4];
     1426
     1427          iMBuff->focusAxi  = sc_.sc_cal[iOff + 5] * 1e-3;
     1428          iMBuff->focusTan  = sc_.sc_cal[iOff + 6] * 1e-3;
     1429          iMBuff->focusRot  = sc_.sc_cal[iOff + 7];
     1430
     1431          iMBuff->temp      = sc_.sc_cal[iOff + 8];
     1432          iMBuff->pressure  = sc_.sc_cal[iOff + 9];
     1433          iMBuff->humidity  = sc_.sc_cal[iOff + 10];
     1434          iMBuff->windSpeed = sc_.sc_cal[iOff + 11];
     1435          iMBuff->windAz    = sc_.sc_cal[iOff + 12];
     1436
     1437          char *tcalTime = iMBuff->tcalTime;
     1438          sprintf(tcalTime, "%-16.16s", (char *)(&sc_.sc_cal[iOff+13]));
     1439          tcalTime[16] = '\0';
    10961440
    10971441#ifndef AIPS_LITTLE_ENDIAN
    1098         // Do byte swapping on the ASCII date string.
    1099         for (int j = 0; j < 16; j += 4) {
    1100           char ctmp;
    1101           ctmp = tcalTime[j];
    1102           tcalTime[j]   = tcalTime[j+3];
    1103           tcalTime[j+3] = ctmp;
    1104           ctmp = tcalTime[j+1];
    1105           tcalTime[j+1] = tcalTime[j+2];
    1106           tcalTime[j+2] = ctmp;
    1107         }
     1442          // Do byte swapping on the ASCII date string.
     1443          for (int j = 0; j < 16; j += 4) {
     1444            char ctmp;
     1445            ctmp = tcalTime[j];
     1446            tcalTime[j]   = tcalTime[j+3];
     1447            tcalTime[j+3] = ctmp;
     1448            ctmp = tcalTime[j+1];
     1449            tcalTime[j+1] = tcalTime[j+2];
     1450            tcalTime[j+2] = ctmp;
     1451          }
    11081452#endif
    11091453
    1110         // Reference beam number.
    1111         float refbeam = sc_.sc_cal[iOff + 17];
    1112         if (refbeam > 0.0f || refbeam < 100.0f) {
    1113           iMBuff->refBeam = int(refbeam);
    1114         } else {
    1115           iMBuff->refBeam = 0;
     1454          // Reference beam number.
     1455          float refbeam = sc_.sc_cal[iOff + 17];
     1456          if (refbeam > 0.0f || refbeam < 100.0f) {
     1457            iMBuff->refBeam = int(refbeam);
     1458          } else {
     1459            iMBuff->refBeam = 0;
     1460          }
    11161461        }
    11171462      }
     
    11281473int MBFITSreader::rpget(int syscalonly, int &EOS)
    11291474{
     1475  const string methodName = "rpget()" ;
     1476  LogIO os( LogOrigin( className, methodName, WHERE ) ) ;
     1477
    11301478  EOS = 0;
    11311479
     
    11351483  int numErr = 0;
    11361484
    1137   jstat = 0;
     1485  int jstat = 0;
    11381486  while (numErr < 10) {
    11391487    int lastjstat = jstat;
    1140     rpfitsin_(&jstat, cVis, weight, &baseline, &ut, &u, &v, &w, &flag, &bin,
    1141               &if_no, &sourceno);
    1142 
    1143     switch(jstat) {
     1488
     1489    switch(rpfitsin(jstat)) {
    11441490    case -1:
    11451491      // Read failed; retry.
    11461492      numErr++;
    1147       fprintf(stderr, "RPFITS read failed - retrying.\n");
     1493      os << LogIO::WARN << "RPFITS read failed - retrying." << LogIO::POST ;
    11481494      jstat = 0;
    11491495      break;
     
    11521498      // Successful read.
    11531499      if (lastjstat == 0) {
    1154         if (baseline == -1) {
     1500        if (cBaseline == -1) {
    11551501          // Syscal data.
    11561502          if (syscalonly) {
     
    12011547    default:
    12021548      // Shouldn't reach here.
    1203       fprintf(stderr, "Unrecognized RPFITSIN return code: %d (retrying)\n",
    1204               jstat);
     1549      sprintf(cMsg, "Unrecognized RPFITSIN return code: %d "
     1550                    "(retrying).", jstat);
     1551      os << LogIO::WARN << cMsg << LogIO::POST ;
    12051552      jstat = 0;
    12061553      break;
     
    12081555  }
    12091556
    1210   fprintf(stderr, "RPFITS read failed too many times.\n");
     1557  os << LogIO::SEVERE << "RPFITS read failed too many times." << LogIO::POST ;
    12111558  return 2;
     1559}
     1560
     1561//----------------------------------------------------- MBFITSreader::rpfitsin
     1562
     1563// Wrapper around RPFITSIN that reports errors.  Returned RPFITSIN subroutine
     1564// arguments are captured as MBFITSreader member variables.
     1565
     1566int MBFITSreader::rpfitsin(int &jstat)
     1567
     1568{
     1569  rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
     1570            &cBin, &cIFno, &cSrcNo);
     1571
     1572  // Handle messages from RPFITSIN.
     1573/**
     1574  if (names_.errmsg[0] != ' ') {
     1575    int i;
     1576    for (i = 80; i > 0; i--) {
     1577      if (names_.errmsg[i-1] != ' ') break;
     1578    }
     1579
     1580    sprintf(cMsg, "WARNING: Cycle %d:%03d, RPFITSIN reported -\n"
     1581                  "         %.*s", cScanNo, cCycleNo, i, names_.errmsg);
     1582    logMsg(cMsg);
     1583  }
     1584**/
     1585  return jstat;
     1586}
     1587
     1588//------------------------------------------------------- MBFITSreader::fixPos
     1589
     1590// Check and, if necessary, repair a position timestamp.
     1591//
     1592// Problems with the position timestamp manifest themselves via the scan rate:
     1593//
     1594//   1) Zero scan rate pairs, 1997/02/28 to 1998/01/07
     1595//
     1596//      These occur because the position timestamp for the first integration
     1597//      of the pair is erroneous; the value recorded is t/1000, where t is the
     1598//      true value.
     1599//        Earliest known: 97-02-28_1725_132653-42_258a.hpf
     1600//          Latest known: 98-01-02_1923_095644-50_165c.hpf
     1601//        (time range chosen to encompass observing runs).
     1602//
     1603//   2) Slow-fast scan rate pairs (0.013 - 0.020 deg/s),
     1604//        1997/03/28 to 1998/01/07.
     1605//
     1606//      The UTC position timestamp is 1.0s later than it should be (never
     1607//      earlier), almost certainly arising from an error in the telescope
     1608//      control system.
     1609//        Earliest known: 97-03-28_0150_010420-74_008d.hpf
     1610//          Latest known: 98-01-04_1502_065150-02_177c.hpf
     1611//        (time range chosen to encompass observing runs).
     1612//
     1613//   3) Slow-fast scan rate pairs (0.015 - 0.018 deg/s),
     1614//        1999/05/20 to 2001/07/12 (HIPASS and ZOA),
     1615//        2001/09/02 to 2001/12/04 (HIPASS and ZOA),
     1616//        2002/03/28 to 2002/05/13 (ZOA only),
     1617//        2003/04/26 to 2003/06/09 (ZOA only).
     1618//        Earliest known: 1999-05-20_1818_175720-50_297e.hpf
     1619//          Latest known: 2001-12-04_1814_065531p14_173e.hpf (HIPASS)
     1620//                        2003-06-09_1924_352-085940_-6c.hpf (ZOA)
     1621//
     1622//      Caused by the Linux signalling NaN problem.  IEEE "signalling" NaNs
     1623//      are silently transformed to "quiet" NaNs during assignment by setting
     1624//      bit 22.  This affected RPFITS because of its use of VAX-format
     1625//      floating-point numbers which, with their permuted bytes, may sometimes
     1626//      appear as signalling NaNs.
     1627//
     1628//      The problem arose when the linux correlator came online and was
     1629//      fixed with a workaround to the RPFITS library (repeated episodes
     1630//      are probably due to use of an older version of the library).  It
     1631//      should not have affected the data significantly because of the
     1632//      low relative error, which ranges from 0.0000038 to 0.0000076, but
     1633//      it is important for the computation of scan rates which requires
     1634//      taking the difference of two large UTC timestamps, one or other
     1635//      of which will have 0.5s added to it.
     1636//
     1637// The return value identifies which, if any, of these problems was repaired.
     1638
     1639int MBFITSreader::fixw(
     1640  const char *datobs,
     1641  int    cycleNo,
     1642  int    beamNo,
     1643  double avRate[2],
     1644  double thisRA,
     1645  double thisDec,
     1646  double thisUTC,
     1647  double nextRA,
     1648  double nextDec,
     1649  float &nextUTC)
     1650{
     1651  if (strcmp(datobs, "2003-06-09") > 0) {
     1652    return 0;
     1653
     1654  } else if (strcmp(datobs, "1998-01-07") <= 0) {
     1655    if (nextUTC < thisUTC && (nextUTC + 86400.0) > (thisUTC + 600.0)) {
     1656      // Possible scaling problem.
     1657      double diff = nextUTC*1000.0 - thisUTC;
     1658      if (0.0 < diff && diff < 600.0) {
     1659        nextUTC *= 1000.0;
     1660        return 1;
     1661      } else {
     1662        // Irreparable.
     1663        return -1;
     1664      }
     1665    }
     1666
     1667    if (cycleNo > 2) {
     1668      if (beamNo == 1) {
     1669        // This test is only reliable for beam 1.
     1670        double dUTC = nextUTC - thisUTC;
     1671        if (dUTC < 0.0) dUTC += 86400.0;
     1672
     1673        // Guard against RA cycling through 24h in either direction.
     1674        if (fabs(nextRA - thisRA) > PI) {
     1675          if (nextRA < thisRA) {
     1676            nextRA += TWOPI;
     1677          } else {
     1678            nextRA -= TWOPI;
     1679          }
     1680        }
     1681
     1682        double  dRA = (nextRA  - thisRA) * cos(nextDec);
     1683        double dDec =  nextDec - thisDec;
     1684        double  arc = sqrt(dRA*dRA + dDec*dDec);
     1685
     1686        double averate = sqrt(avRate[0]*avRate[0] + avRate[1]*avRate[1]);
     1687        double diff1 = fabs(averate - arc/(dUTC-1.0));
     1688        double diff2 = fabs(averate - arc/dUTC);
     1689        if ((diff1 < diff2) && (diff1 < 0.05*averate)) {
     1690          nextUTC -= 1.0;
     1691          cCode5 = cycleNo;
     1692          return 2;
     1693        } else {
     1694          cCode5 = 0;
     1695        }
     1696
     1697      } else {
     1698        if (cycleNo == cCode5) {
     1699          nextUTC -= 1.0;
     1700          return 2;
     1701        }
     1702      }
     1703    }
     1704
     1705  } else if ((strcmp(datobs, "1999-05-20") >= 0 &&
     1706              strcmp(datobs, "2001-07-12") <= 0) ||
     1707             (strcmp(datobs, "2001-09-02") >= 0 &&
     1708              strcmp(datobs, "2001-12-04") <= 0) ||
     1709             (strcmp(datobs, "2002-03-28") >= 0 &&
     1710              strcmp(datobs, "2002-05-13") <= 0) ||
     1711             (strcmp(datobs, "2003-04-26") >= 0 &&
     1712              strcmp(datobs, "2003-06-09") <= 0)) {
     1713    // Signalling NaN problem, e.g. 1999-07-26_1839_011106-74_009c.hpf.
     1714    // Position timestamps should always be an integral number of seconds.
     1715    double resid = nextUTC - int(nextUTC);
     1716    if (resid == 0.5) {
     1717      nextUTC -= 0.5;
     1718      return 3;
     1719    }
     1720  }
     1721
     1722  return 0;
    12121723}
    12131724
     
    12191730{
    12201731  if (cMBopen) {
    1221     jstat = 1;
    1222     rpfitsin_(&jstat, cVis, weight, &baseline, &ut, &u, &v, &w, &flag, &bin,
    1223               &if_no, &sourceno);
     1732    int jstat = 1;
     1733    rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
     1734              &cBin, &cIFno, &cSrcNo);
    12241735
    12251736    if (cBeams)     delete [] cBeams;
     
    12321743    if (cRefChan)   delete [] cRefChan;
    12331744
    1234     if (cVis)       delete [] cVis;
     1745    if (cVis) delete [] cVis;
     1746    if (cWgt) delete [] cWgt;
    12351747
    12361748    if (cBeamSel)   delete [] cBeamSel;
     
    12441756  }
    12451757}
     1758
     1759//-------------------------------------------------------------------- utcDiff
     1760
     1761// Subtract two UTCs (s) allowing for any plausible number of cycles through
     1762// 86400s, returning a result in the range [-43200, +43200]s.
     1763
     1764double MBFITSreader::utcDiff(double utc1, double utc2)
     1765{
     1766  double diff = utc1 - utc2;
     1767
     1768  if (diff > 43200.0) {
     1769    diff -= 86400.0;
     1770    while (diff > 43200.0) diff -= 86400.0;
     1771  } else if (diff < -43200.0) {
     1772    diff += 86400.0;
     1773    while (diff < -43200.0) diff += 86400.0;
     1774  }
     1775
     1776  return diff;
     1777}
     1778
     1779//------------------------------------------------------- scanRate & applyRate
     1780
     1781// Compute and apply the scan rate corrected for grid convergence.  (ra0,dec0)
     1782// are the coordinates of the central beam, assumed to be the tracking centre.
     1783// The rate computed in RA will be a rate of change of angular distance in the
     1784// direction of increasing RA at the position of the central beam.  Similarly
     1785// for declination.  Angles in radian, time in s.
     1786
     1787void MBFITSreader::scanRate(
     1788  double ra0,
     1789  double dec0,
     1790  double ra1,
     1791  double dec1,
     1792  double ra2,
     1793  double dec2,
     1794  double dt,
     1795  double &raRate,
     1796  double &decRate)
     1797{
     1798  // Transform to a system where the central beam lies on the equator at 12h.
     1799  eulerx(ra1, dec1, ra0+HALFPI, -dec0, -HALFPI, ra1, dec1);
     1800  eulerx(ra2, dec2, ra0+HALFPI, -dec0, -HALFPI, ra2, dec2);
     1801
     1802  raRate  = (ra2  - ra1)  / dt;
     1803  decRate = (dec2 - dec1) / dt;
     1804}
     1805
     1806
     1807void MBFITSreader::applyRate(
     1808  double ra0,
     1809  double dec0,
     1810  double ra1,
     1811  double dec1,
     1812  double raRate,
     1813  double decRate,
     1814  double dt,
     1815  double &ra2,
     1816  double &dec2)
     1817{
     1818  // Transform to a system where the central beam lies on the equator at 12h.
     1819  eulerx(ra1, dec1, ra0+HALFPI, -dec0, -HALFPI, ra1, dec1);
     1820
     1821  ra2  = ra1  + (raRate  * dt);
     1822  dec2 = dec1 + (decRate * dt);
     1823
     1824  // Transform back.
     1825  eulerx(ra2, dec2, -HALFPI, dec0, ra0+HALFPI, ra2, dec2);
     1826}
     1827
     1828//--------------------------------------------------------------------- eulerx
     1829
     1830void MBFITSreader::eulerx(
     1831  double lng0,
     1832  double lat0,
     1833  double phi0,
     1834  double theta,
     1835  double phi,
     1836  double &lng1,
     1837  double &lat1)
     1838
     1839// Applies the Euler angle based transformation of spherical coordinates.
     1840//
     1841//     phi0  Longitude of the ascending node in the old system, radians.  The
     1842//           ascending node is the point of intersection of the equators of
     1843//           the two systems such that the equator of the new system crosses
     1844//           from south to north as viewed in the old system.
     1845//
     1846//    theta  Angle between the poles of the two systems, radians.  THETA is
     1847//           positive for a positive rotation about the ascending node.
     1848//
     1849//      phi  Longitude of the ascending node in the new system, radians.
     1850
     1851{
     1852  // Compute intermediaries.
     1853  double lng0p  = lng0 - phi0;
     1854  double slng0p = sin(lng0p);
     1855  double clng0p = cos(lng0p);
     1856  double slat0  = sin(lat0);
     1857  double clat0  = cos(lat0);
     1858  double ctheta = cos(theta);
     1859  double stheta = sin(theta);
     1860
     1861  double x = clat0*clng0p;
     1862  double y = clat0*slng0p*ctheta + slat0*stheta;
     1863
     1864  // Longitude in the new system.
     1865  if (x != 0.0 || y != 0.0) {
     1866    lng1 = phi + atan2(y, x);
     1867  } else {
     1868    // Longitude at the poles in the new system is consistent with that
     1869    // specified in the old system.
     1870    lng1 = phi + lng0p;
     1871  }
     1872  lng1 = fmod(lng1, TWOPI);
     1873  if (lng1 < 0.0) lng1 += TWOPI;
     1874
     1875  lat1 = asin(slat0*ctheta - clat0*stheta*slng0p);
     1876}
Note: See TracChangeset for help on using the changeset viewer.