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/SDFITSreader.cc

    r1453 r1757  
    11//#---------------------------------------------------------------------------
    2 //# SDFITSreader.cc: ATNF CFITSIO interface class for SDFITS input.
     2//# SDFITSreader.cc: ATNF interface class for SDFITS input using CFITSIO.
    33//#---------------------------------------------------------------------------
    4 //# Copyright (C) 2000-2006
    5 //# Associated Universities, Inc. Washington DC, USA.
     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: aips2-request@nrao.edu.
    23 //#        Postal address: AIPS++ Project Office
    24 //#                        National Radio Astronomy Observatory
    25 //#                        520 Edgemont Road
    26 //#                        Charlottesville, VA 22903-2475 USA
     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
     28//#                        AUSTRALIA
    2729//#
    28 //# $Id$
     30//# http://www.atnf.csiro.au/computing/software/livedata.html
     31//# $Id: SDFITSreader.cc,v 19.45 2009-09-30 07:23:48 cal103 Exp $
    2932//#---------------------------------------------------------------------------
    3033//# The SDFITSreader class reads single dish FITS files such as those written
     
    3437//#---------------------------------------------------------------------------
    3538
     39#include <atnf/pks/pks_maths.h>
     40#include <atnf/PKSIO/MBrecord.h>
     41#include <atnf/PKSIO/SDFITSreader.h>
     42
     43#include <casa/Logging/LogIO.h>
     44#include <casa/Quanta/MVTime.h>
     45#include <casa/math.h>
     46#include <casa/stdio.h>
     47
    3648#include <algorithm>
    3749#include <strings.h>
    38 
    39 // AIPS++ includes.
    40 #include <casa/iostream.h>
    41 #include <casa/math.h>
    42 #include <casa/stdio.h>
    43 
    44 // ATNF includes.
    45 #include <atnf/pks/pks_maths.h>
    46 #include <atnf/PKSIO/PKSMBrecord.h>
    47 #include <atnf/PKSIO/SDFITSreader.h>
    48 
     50#include <cstring>
    4951
    5052class FITSparm
     
    5759    long nelem;         // Column data repeat count; < 0 for vardim.
    5860    int  tdimcol;       // TDIM column number; 0 for keyword; -1 absent.
     61    char units[32];     // Units from TUNITn keyword.
    5962};
    6063
     
    6467// Factor to convert radians to degrees.
    6568const double D2R = PI / 180.0;
     69
     70// Class name
     71const string className = "SDFITSreader" ;
     72
     73//---------------------------------------------------- SDFITSreader::(statics)
     74
     75int SDFITSreader::sInit  = 1;
     76int SDFITSreader::sReset = 0;
     77int (*SDFITSreader::sALFAcalNon)[2]   = (int (*)[2])(new float[16]);
     78int (*SDFITSreader::sALFAcalNoff)[2]  = (int (*)[2])(new float[16]);
     79float (*SDFITSreader::sALFAcalOn)[2]  = (float (*)[2])(new float[16]);
     80float (*SDFITSreader::sALFAcalOff)[2] = (float (*)[2])(new float[16]);
     81float (*SDFITSreader::sALFAcal)[2]    = (float (*)[2])(new float[16]);
    6682
    6783//------------------------------------------------- SDFITSreader::SDFITSreader
     
    7086{
    7187  // Default constructor.
    72   cSDptr = 0;
     88  cSDptr = 0x0;
    7389
    7490  // Allocate space for data descriptors.
     
    85101  cEndChan   = 0x0;
    86102  cRefChan   = 0x0;
     103  cPols      = 0x0;
    87104}
    88105
     
    113130        int    &extraSysCal)
    114131{
     132  const string methodName = "open()" ;
     133
    115134  if (cSDptr) {
    116135    close();
     
    120139  cStatus = 0;
    121140  if (fits_open_file(&cSDptr, sdName, READONLY, &cStatus)) {
    122     cerr << "Failed to open SDFITS file: " << sdName << endl;
    123     reportError();
     141    sprintf(cMsg, "ERROR: Failed to open SDFITS file\n       %s", sdName);
     142    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, cMsg);
    124143    return 1;
    125144  }
     
    138157        cALFA_CIMA = 1;
    139158
     159        // Check for later versions of CIMAFITS.
     160        float version;
     161        readParm("VERSION", TFLOAT, &version);
     162        if (version >= 2.0f) cALFA_CIMA = int(version);
     163
    140164      } else {
    141         cerr << "Failed to locate SDFITS binary table." << endl;
    142         reportError();
     165        log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "Failed to locate SDFITS binary table.");
    143166        close();
    144167        return 1;
     
    148171    // Arecibo ALFA data of some kind.
    149172    cALFA = 1;
    150     for (int iBeam = 0; iBeam < 8; iBeam++) {
    151       for (int iPol = 0; iPol < 2; iPol++) {
    152         cALFAcalOn[iBeam][iPol]  = 0.0f;
    153         cALFAcalOff[iBeam][iPol] = 0.0f;
    154 
    155         // Nominal factor to calibrate spectra in Jy.
    156         cALFAcal[iBeam][iPol] = 3.0f;
    157       }
     173    if (sInit) {
     174      for (int iBeam = 0; iBeam < 8; iBeam++) {
     175        for (int iPol = 0; iPol < 2; iPol++) {
     176          sALFAcalOn[iBeam][iPol]  = 0.0f;
     177          sALFAcalOff[iBeam][iPol] = 0.0f;
     178
     179          // Nominal factor to calibrate spectra in Jy.
     180          sALFAcal[iBeam][iPol] = 3.0f;
     181        }
     182      }
     183
     184      sInit = 0;
    158185    }
    159186  }
     
    165192         strncmp(telescope, "NRAO_GBT", 8) == 0;
    166193
    167   cRow = 0;
    168 
    169194
    170195  // Check that the DATA array column is present.
     
    172197  haveSpectra = cHaveSpectra = cData[DATA].colnum > 0;
    173198
     199  cNAxisTime = 0;
    174200  if (cHaveSpectra) {
    175201    // Find the number of data axes (must be the same for each IF).
    176     cNAxis = 5;
    177     if (readDim(DATA, 1, &cNAxis, cNAxes)) {
    178       reportError();
     202    cNAxes = 5;
     203    if (readDim(DATA, 1, &cNAxes, cNAxis)) {
     204      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    179205      close();
    180206      return 1;
     
    182208
    183209    if (cALFA_BD) {
    184       // ALFA BDFITS: variable length arrays don't actually vary and there is 
     210      // ALFA BDFITS: variable length arrays don't actually vary and there is
    185211      // no TDIM (or MAXISn) card; use the LAGS_IN value.
    186       cNAxis = 5;
    187       readParm("LAGS_IN", TLONG, cNAxes);
    188       cNAxes[1] = 1;
    189       cNAxes[2] = 1;
    190       cNAxes[3] = 1;
    191       cNAxes[4] = 1;
    192       cData[DATA].nelem = cNAxes[0];
    193     }
    194 
    195     if (cNAxis < 4) {
     212      cNAxes = 5;
     213      readParm("LAGS_IN", TLONG, cNAxis);
     214      cNAxis[1] = 1;
     215      cNAxis[2] = 1;
     216      cNAxis[3] = 1;
     217      cNAxis[4] = 1;
     218      cData[DATA].nelem = cNAxis[0];
     219    }
     220
     221    if (cNAxes < 4) {
    196222      // Need at least four axes (for now).
    197       cerr << "DATA array contains fewer than four axes." << endl;
     223      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "DATA array contains fewer than four axes.");
    198224      close();
    199225      return 1;
    200     } else if (cNAxis > 5) {
     226    } else if (cNAxes > 5) {
    201227      // We support up to five axes.
    202       cerr << "DATA array contains more than five axes." << endl;
     228      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "DATA array contains more than five axes.");
    203229      close();
    204230      return 1;
     
    211237    findData(DATAXED, "DATAXED", TSTRING);
    212238    if (cData[DATAXED].colnum < 0) {
    213       cerr << "DATA array column absent from binary table." << endl;
     239      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "DATA array column absent from binary table.");
    214240      close();
    215241      return 1;
     
    220246    readParm("DATAXED", TSTRING, dataxed);
    221247
    222     for (int iaxis = 0; iaxis < 5; iaxis++) cNAxes[iaxis] = 0;
    223     sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAxes, cNAxes+1, cNAxes+2,
    224       cNAxes+3, cNAxes+4);
     248    for (int iaxis = 0; iaxis < 5; iaxis++) cNAxis[iaxis] = 0;
     249    sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAxis, cNAxis+1, cNAxis+2,
     250      cNAxis+3, cNAxis+4);
    225251    for (int iaxis = 4; iaxis > -1; iaxis--) {
    226       if (cNAxes[iaxis] == 0) cNAxis = iaxis;
     252      if (cNAxis[iaxis] == 0) cNAxes = iaxis;
    227253    }
    228254  }
     
    235261  // Find required DATA array axes.
    236262  char ctype[5][72];
    237   for (int iaxis = 0; iaxis < cNAxis; iaxis++) {
     263  for (int iaxis = 0; iaxis < cNAxes; iaxis++) {
    238264    strcpy(ctype[iaxis], "");
    239265    readParm(CTYPE[iaxis], TSTRING, ctype[iaxis]);      // Core.
     
    241267
    242268  if (cStatus) {
    243     reportError();
     269    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    244270    close();
    245271    return 1;
    246272  }
    247273
    248   char *fqCRPIX  = 0;
    249274  char *fqCRVAL  = 0;
    250275  char *fqCDELT  = 0;
     276  char *fqCRPIX  = 0;
    251277  char *raCRVAL  = 0;
    252278  char *decCRVAL = 0;
    253279  char *timeCRVAL = 0;
     280  char *timeCDELT = 0;
     281  char *timeCRPIX = 0;
    254282  char *beamCRVAL = 0;
    255 
    256   for (int iaxis = 0; iaxis < cNAxis; iaxis++) {
     283  char *polCRVAL = 0;
     284
     285  cFreqAxis   = -1;
     286  cStokesAxis = -1;
     287  cRaAxis     = -1;
     288  cDecAxis    = -1;
     289  cTimeAxis   = -1;
     290  cBeamAxis   = -1;
     291
     292  for (int iaxis = 0; iaxis < cNAxes; iaxis++) {
    257293    if (strncmp(ctype[iaxis], "FREQ", 4) == 0) {
    258       cReqax[0] = iaxis;
    259       fqCRPIX  = CRPIX[iaxis];
    260       fqCRVAL  = CRVAL[iaxis];
    261       fqCDELT  = CDELT[iaxis];
     294      cFreqAxis = iaxis;
     295      fqCRVAL   = CRVAL[iaxis];
     296      fqCDELT   = CDELT[iaxis];
     297      fqCRPIX   = CRPIX[iaxis];
    262298
    263299    } else if (strncmp(ctype[iaxis], "STOKES", 6) == 0) {
    264       cReqax[1] = iaxis;
     300      cStokesAxis = iaxis;
     301      polCRVAL = CRVAL[iaxis];
    265302
    266303    } else if (strncmp(ctype[iaxis], "RA", 2) == 0) {
    267       cReqax[2] = iaxis;
    268       raCRVAL  = CRVAL[iaxis];
     304      cRaAxis  = iaxis;
     305      raCRVAL   = CRVAL[iaxis];
    269306
    270307    } else if (strncmp(ctype[iaxis], "DEC", 3) == 0) {
    271       cReqax[3] = iaxis;
    272       decCRVAL = CRVAL[iaxis];
     308      cDecAxis = iaxis;
     309      decCRVAL  = CRVAL[iaxis];
    273310
    274311    } else if (strcmp(ctype[iaxis], "TIME") == 0) {
    275       // TIME (UTC seconds since midnight) can be a keyword or axis type.
     312      // TIME (UTC seconds since midnight); axis type, if present, takes
     313      // precedence over keyword.
     314      cTimeAxis = iaxis;
    276315      timeCRVAL = CRVAL[iaxis];
     316
     317      // Check for non-degeneracy.
     318      if ((cNAxisTime = cNAxis[iaxis]) > 1) {
     319        timeCDELT = CDELT[iaxis];
     320        timeCRPIX = CRPIX[iaxis];
     321        sprintf(cMsg, "DATA array contains a TIME axis of length %ld.",
     322          cNAxisTime);
     323        //logMsg(cMsg);
     324        log(LogOrigin( className, methodName, WHERE ), LogIO::NORMAL, cMsg);
     325      }
    277326
    278327    } else if (strcmp(ctype[iaxis], "BEAM") == 0) {
    279328      // BEAM can be a keyword or axis type.
     329      cBeamAxis = iaxis;
    280330      beamCRVAL = CRVAL[iaxis];
    281331    }
     
    284334  if (cALFA_BD) {
    285335    // Fixed in ALFA CIMAFITS.
    286     cReqax[2] = 2;
     336    cRaAxis = 2;
    287337    raCRVAL = "CRVAL2A";
    288338
    289     cReqax[3] = 3;
     339    cDecAxis = 3;
    290340    decCRVAL = "CRVAL3A";
    291341  }
    292342
    293   // Check that all are present.
    294   for (int iaxis = 0; iaxis < 4; iaxis++) {
    295     if (cReqax[iaxis] < 0) {
    296       cerr << "Could not find required DATA array axes." << endl;
    297       close();
    298       return 1;
    299     }
     343
     344  // Check that required axes are present.
     345  if (cFreqAxis < 0 || cStokesAxis < 0 || cRaAxis < 0 || cDecAxis < 0) {
     346    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "Could not find required DATA array axes.");
     347    close();
     348    return 1;
    300349  }
    301350
     
    304353  findData(CYCLE,    "CYCLE",    TINT);         // Additional.
    305354  findData(DATE_OBS, "DATE-OBS", TSTRING);      // Core.
    306   findData(TIME,     "TIME",     TDOUBLE);      // Core.
     355
     356  if (cTimeAxis >= 0) {
     357    // The DATA array has a TIME axis.
     358    if (cNAxisTime > 1) {
     359      // Non-degenerate.
     360      findData(TimeRefVal, timeCRVAL, TDOUBLE); // Time reference value.
     361      findData(TimeDelt,   timeCDELT, TDOUBLE); // Time increment.
     362      findData(TimeRefPix, timeCRPIX, TFLOAT);  // Time reference pixel.
     363    } else {
     364      // Degenerate, treat its like a simple TIME keyword.
     365      findData(TIME, timeCRVAL,  TDOUBLE);
     366    }
     367
     368  } else {
     369    findData(TIME,   "TIME",     TDOUBLE);      // Core.
     370  }
     371
    307372  findData(EXPOSURE, "EXPOSURE", TFLOAT);       // Core.
    308373  findData(OBJECT,   "OBJECT",   TSTRING);      // Core.
     
    314379  findData(BEAM,     "BEAM",     TSHORT);       // Additional.
    315380  findData(IF,       "IF",       TSHORT);       // Additional.
    316   findData(FqRefPix,  fqCRPIX,   TFLOAT);       // Frequency reference pixel.
    317381  findData(FqRefVal,  fqCRVAL,   TDOUBLE);      // Frequency reference value.
    318382  findData(FqDelt,    fqCDELT,   TDOUBLE);      // Frequency increment.
     383  findData(FqRefPix,  fqCRPIX,   TFLOAT);       // Frequency reference pixel.
    319384  findData(RA,        raCRVAL,   TDOUBLE);      // Right ascension.
    320385  findData(DEC,      decCRVAL,   TDOUBLE);      // Declination.
     
    343408  findData(WINDDIRE, "WINDDIRE", TFLOAT);       // Shared.
    344409
     410  findData(STOKES,    polCRVAL,  TINT);
     411  findData(SIG,       "SIG",     TSTRING);
     412  findData(CAL,       "CAL",     TSTRING);
     413
     414  findData(RVSYS,     "RVSYS",   TDOUBLE);
     415  findData(VFRAME,    "VFRAME",  TDOUBLE);
     416  findData(VELDEF,    "VELDEF",  TSTRING);
     417
    345418  if (cStatus) {
    346     reportError();
     419    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    347420    close();
    348421    return 1;
     
    355428    cALFAscan = 0;
    356429    cScanNo = 0;
    357     if (cALFA_BD) {
     430    if (cALFA_CIMA) {
     431      findData(SCAN,  "SCAN_ID", TINT);
     432      if (cALFA_CIMA > 1) {
     433        // Note that RECNUM increases by cNAxisTime per row.
     434        findData(CYCLE, "RECNUM", TINT);
     435      } else {
     436        findData(CYCLE, "SUBSCAN", TINT);
     437      }
     438    } else if (cALFA_BD) {
    358439      findData(SCAN,  "SCAN_NUMBER", TINT);
    359440      findData(CYCLE, "PATTERN_NUMBER", TINT);
    360     } else if (cALFA_CIMA) {
    361       findData(SCAN,  "SCAN_ID", TINT);
    362       findData(CYCLE, "SUBSCAN", TINT);
    363441    }
    364442  } else {
     
    368446  cCycleNo = 0;
    369447  cLastUTC = 0.0;
     448  for ( int i = 0 ; i < 4 ; i++ ) {
     449    cGLastUTC[i] = 0.0 ;
     450    cGLastScan[i] = -1 ;
     451    cGCycleNo[i] = 0 ;
     452  }
    370453
    371454  // Beam number, 1-relative by default.
    372455  cBeam_1rel = 1;
    373   if (cData[BEAM].colnum < 0) {
     456  if (cALFA) {
     457    // ALFA INPUT_ID, 0-relative (overrides BEAM column if present).
     458    findData(BEAM, "INPUT_ID", TSHORT);
     459    cBeam_1rel = 0;
     460
     461  } else if (cData[BEAM].colnum < 0) {
    374462    if (beamCRVAL) {
    375463      // There is a BEAM axis.
    376464      findData(BEAM, beamCRVAL, TDOUBLE);
    377 
    378465    } else {
    379       if (cALFA) {
    380         // ALFA data, 0-relative.
    381         findData(BEAM, "INPUT_ID", TSHORT);
    382       } else {
    383         // ms2sdfits output, 0-relative "feed" number.
    384         findData(BEAM, "MAIN_FEED1", TSHORT);
    385       }
    386 
     466      // ms2sdfits output, 0-relative "feed" number.
     467      findData(BEAM, "MAIN_FEED1", TSHORT);
    387468      cBeam_1rel = 0;
    388469    }
     
    393474  if (cALFA && cData[IF].colnum < 0) {
    394475    // ALFA data, 0-relative.
    395     findData(IF, "IFVAL", TSHORT);
     476    if (cALFA_CIMA > 1) {
     477      findData(IF, "IFN", TSHORT);
     478    } else {
     479      findData(IF, "IFVAL", TSHORT);
     480    }
    396481    cIF_1rel = 0;
    397   }
    398 
    399   if (cData[TIME].colnum < 0) {
    400     if (timeCRVAL) {
    401       // There is a TIME axis.
    402       findData(TIME, timeCRVAL, TDOUBLE);
    403     }
    404482  }
    405483
     
    476554  fits_get_num_rows(cSDptr, &cNRow, &cStatus);
    477555  if (!cNRow) {
    478     cerr << "Table contains no entries." << endl;
     556    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "Table contains no entries.");
    479557    close();
    480558    return 1;
     
    489567    if (fits_read_col(cSDptr, TSHORT, cData[BEAM].colnum, 1, 1, cNRow,
    490568                      &beamNul, beamCol, &anynul, &cStatus)) {
    491       reportError();
    492569      delete [] beamCol;
     570      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    493571      close();
    494572      return 1;
     
    504582      // Check validity.
    505583      if (beamCol[irow] < cBeam_1rel) {
    506         cerr << "SDFITS file contains invalid beam number." << endl;
    507584        delete [] beamCol;
     585        log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "SDFITS file contains invalid beam number.");
    508586        close();
    509587        return 1;
     
    545623    if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow,
    546624                      &IFNul, IFCol, &anynul, &cStatus)) {
    547       reportError();
    548625      delete [] IFCol;
     626      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    549627      close();
    550628      return 1;
     
    560638      // Check validity.
    561639      if (IFCol[irow] < cIF_1rel) {
    562         cerr << "SDFITS file contains invalid IF number." << endl;
    563640        delete [] IFCol;
     641        log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "SDFITS file contains invalid IF number.");
    564642        close();
    565643        return 1;
     
    592670          if (cData[DATA].nelem < 0) {
    593671            // Variable dimension array.
    594             if (readDim(DATA, irow+1, &cNAxis, cNAxes)) {
    595               reportError();
     672            if (readDim(DATA, irow+1, &cNAxes, cNAxis)) {
     673              log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    596674              close();
    597675              return 1;
     
    604682            readParm("DATAXED", TSTRING, dataxed);
    605683
    606             sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAxes, cNAxes+1,
    607               cNAxes+2, cNAxes+3, cNAxes+4);
     684            sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAxis, cNAxis+1,
     685              cNAxis+2, cNAxis+3, cNAxis+4);
    608686          }
    609687        }
    610688
    611689        // Number of channels and polarizations.
    612         cNChan[iIF]    = cNAxes[cReqax[0]];
    613         cNPol[iIF]     = cNAxes[cReqax[1]];
     690        cNChan[iIF]    = cNAxis[cFreqAxis];
     691        cNPol[iIF]     = cNAxis[cStokesAxis];
    614692        cHaveXPol[iIF] = 0;
    615693
     
    621699
    622700          if (readDim(XPOLDATA, irow+1, &nAxis, nAxes)) {
    623             reportError();
     701            log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE );
    624702            close();
    625703            return 1;
     
    650728
    651729    // Number of channels and polarizations.
    652     cNChan[0] = cNAxes[cReqax[0]];
    653     cNPol[0]  = cNAxes[cReqax[1]];
     730    cNChan[0] = cNAxis[cFreqAxis];
     731    cNPol[0]  = cNAxis[cStokesAxis];
    654732    cHaveXPol[0] = 0;
    655733  }
    656734
    657   if (cALFA) {
    658     // ALFA labels each polarization as a separate IF.
     735  if (cALFA && cALFA_CIMA < 2) {
     736    // Older ALFA data labels each polarization as a separate IF.
    659737    cNPol[0] = cNIF;
    660738    cNIF = 1;
     739  }
     740
     741  // For GBT data that stores spectra for each polarization in separate rows
     742  if ( cData[STOKES].colnum > 0 ) {
     743    int *stokesCol = new int[cNRow];
     744    int stokesNul = 1;
     745    int   anynul;
     746    if (fits_read_col(cSDptr, TINT, cData[STOKES].colnum, 1, 1, cNRow,
     747                      &stokesNul, stokesCol, &anynul, &cStatus)) {
     748      delete [] stokesCol;
     749      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
     750      close();
     751      return 1;
     752    }
     753
     754    vector<int> pols ;
     755    pols.push_back( stokesCol[0] ) ;
     756    for ( int i = 0 ; i < cNRow ; i++ ) {
     757      bool pmatch = false ;
     758      for ( uint j = 0 ; j < pols.size() ; j++ ) {
     759        if ( stokesCol[i] == pols[j] ) {
     760          pmatch = true ;
     761          break ;
     762        }
     763      }
     764      if ( !pmatch ) {
     765        pols.push_back( stokesCol[i] ) ;
     766      }
     767    }
     768
     769    cPols = new int[pols.size()] ;
     770    for ( uint i = 0 ; i < pols.size() ; i++ ) {
     771      cPols[i] = pols[i] ;
     772    }
     773
     774    for ( int i = 0 ; i < cNIF ; i++ ) {
     775      cNPol[i] = pols.size() ;
     776    }
     777
     778    delete [] stokesCol ;
    661779  }
    662780
     
    712830  extraSysCal = cExtraSysCal;
    713831
     832
     833  // Extras for ALFA data.
     834  cALFAacc = 0.0f;
     835  if (cALFA_CIMA > 1) {
     836    // FFTs per second when the Mock correlator operates in RFI blanking mode.
     837    readData("PHFFTACC", TFLOAT, 0, &cALFAacc);
     838  }
     839
     840
     841  cRow = 0;
     842  cTimeIdx = cNAxisTime;
     843
    714844  return 0;
    715845}
     
    725855        double antPos[3],
    726856        char   obsMode[32],
     857        char   bunit[32],
    727858        float  &equinox,
    728859        char   radecsys[32],
     
    733864        double &bandwidth)
    734865{
     866  const string methodName = "getHeader()" ;
     867 
    735868  // Has the file been opened?
    736869  if (!cSDptr) {
     
    773906  readData(OBSMODE, 1, obsMode);                        // Shared.
    774907
     908  // Brightness unit.
     909  if (cData[DATAXED].colnum >= 0) {
     910    strcpy(bunit, "Jy");
     911  } else {
     912    strcpy(bunit, cData[DATA].units);
     913  }
     914
     915  if (strcmp(bunit, "JY") == 0) {
     916    bunit[1] = 'y';
     917  } else if (strcmp(bunit, "JY/BEAM") == 0) {
     918    strcpy(bunit, "Jy/beam");
     919  }
     920
    775921  readParm("EQUINOX",  TFLOAT,  &equinox);              // Shared.
    776922  if (cStatus == 405) {
     
    793939
    794940    // Look for VELFRAME, written by earlier versions of Livedata.
     941    //
     942    // Added few more codes currently (as of 2009 Oct) used in the GBT
     943    // SDFITS (based io_sdfits_define.pro of GBTIDL). - TT
    795944    if (readParm("VELFRAME", TSTRING, dopplerFrame)) {  // Additional.
    796945      // No, try digging it out of the CTYPE card (AIPS convention).
    797946      char keyw[9], ctype[9];
    798       sprintf(keyw, "CTYPE%ld", cReqax[0]+1);
     947      sprintf(keyw, "CTYPE%ld", cFreqAxis+1);
    799948      readParm(keyw, TSTRING, ctype);
    800949
     
    804953          // LSR unqualified usually means LSR (kinematic).
    805954          strcpy(dopplerFrame, "LSRK");
     955        } else if (strcmp(dopplerFrame, "LSD") == 0) {
     956          // LSR as a dynamical defintion
     957          strcpy(dopplerFrame, "LSRD");
    806958        } else if (strcmp(dopplerFrame, "HEL") == 0) {
    807959          // Almost certainly barycentric.
    808960          strcpy(dopplerFrame, "BARYCENT");
     961        } else if (strcmp(dopplerFrame, "BAR") == 0) {
     962          // barycentric.
     963          strcpy(dopplerFrame, "BARYCENT");
     964        } else if (strcmp(dopplerFrame, "OBS") == 0) {
     965          // observed or topocentric.
     966          strcpy(dopplerFrame, "TOPO");
     967        } else if (strcmp(dopplerFrame, "GEO") == 0) {
     968          // geocentric
     969          strcpy(dopplerFrame, "GEO");
     970        } else if (strcmp(dopplerFrame, "GAL") == 0) {
     971          // galactic
     972          strcpy(dopplerFrame, "GAL");
     973        } else if (strcmp(dopplerFrame, "LGR") == 0) {
     974          // Local group
     975          strcpy(dopplerFrame, "LGROUP");
     976        } else if (strcmp(dopplerFrame, "CMB") == 0) {
     977          // Cosimic Microwave Backgroup
     978          strcpy(dopplerFrame, "CMB");
    809979        }
    810980      } else {
     
    812982      }
    813983    }
    814 
    815984    // Translate to FITS standard names.
    816985    if (strncmp(dopplerFrame, "TOP", 3) == 0) {
     
    822991    } else if (strncmp(dopplerFrame, "BARY", 4) == 0) {
    823992      strcpy(dopplerFrame, "BARYCENT");
    824     }
    825   }
    826 
     993    } else if (strncmp(dopplerFrame, "GAL", 3) == 0) {
     994      strcpy(dopplerFrame, "GALACTOC");
     995    } else if (strncmp(dopplerFrame, "LGROUP", 6) == 0) {
     996      strcpy(dopplerFrame, "LOCALGRP");
     997    } else if (strncmp(dopplerFrame, "CMB", 3) == 0) {
     998      strcpy(dopplerFrame, "CMBDIPOL");
     999    }
     1000  }
     1001 
    8271002  if (cStatus) {
    828     reportError();
     1003    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    8291004    return 1;
    8301005  }
    8311006
    8321007  // Get parameters from first row of table.
    833   readData(DATE_OBS, 1, datobs);
    834   readData(TIME,     1, &utc);
     1008  readTime(1, 1, datobs, utc);
    8351009  readData(FqRefVal, 1, &refFreq);
    8361010  readParm("BANDWID", TDOUBLE, &bandwidth);             // Core.
    8371011
    838   if (cALFA_BD) utc *= 3600.0;
    839 
    8401012  if (cStatus) {
    841     reportError();
     1013    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    8421014    return 1;
    843   }
    844 
    845   // Check DATE-OBS format.
    846   if (datobs[2] == '/') {
    847     // Translate an old-format DATE-OBS.
    848     datobs[9] = datobs[1];
    849     datobs[8] = datobs[0];
    850     datobs[2] = datobs[6];
    851     datobs[5] = datobs[3];
    852     datobs[3] = datobs[7];
    853     datobs[6] = datobs[4];
    854     datobs[7] = '-';
    855     datobs[4] = '-';
    856     datobs[1] = '9';
    857     datobs[0] = '1';
    858     datobs[10] = '\0';
    859 
    860   } else if (datobs[10] == 'T' && cData[TIME].colnum < 0) {
    861     // Dig UTC out of a new-format DATE-OBS.
    862     int   hh, mm;
    863     float ss;
    864     sscanf(datobs+11, "%d:%d:%f", &hh, &mm, &ss);
    865     utc = (hh*60 + mm)*60 + ss;
    866     datobs[10] = '\0';
    8671015  }
    8681016
     
    8791027        double* &endFreq)
    8801028{
     1029  const string methodName = "getFreqInfo()" ;
     1030
    8811031  float  fqRefPix;
    8821032  double fqDelt, fqRefVal;
     
    8921042    if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow,
    8931043                      &IFNul, IFCol, &anynul, &cStatus)) {
    894       reportError();
    8951044      delete [] IFCol;
     1045      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    8961046      close();
    8971047      return 1;
     
    9561106        double* &positions)
    9571107{
    958   int anynul;
     1108  const string methodName = "findRange()" ;
    9591109
    9601110  // Has the file been opened?
     
    9661116
    9671117  // Find the number of rows selected.
    968   short *sel = new short[nRow];
    969   for (int irow = 0; irow < nRow; irow++) {
     1118  short *sel = new short[cNRow];
     1119  for (int irow = 0; irow < cNRow; irow++) {
    9701120    sel[irow] = 1;
    9711121  }
    9721122
     1123  int anynul;
    9731124  if (cData[BEAM].colnum > 0) {
    9741125    short *beamCol = new short[cNRow];
     
    9761127    if (fits_read_col(cSDptr, TSHORT, cData[BEAM].colnum, 1, 1, cNRow,
    9771128                      &beamNul, beamCol, &anynul, &cStatus)) {
    978       reportError();
    9791129      delete [] beamCol;
    9801130      delete [] sel;
     1131      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    9811132      return 1;
    9821133    }
    9831134
    984     for (int irow = 0; irow < nRow; irow++) {
     1135    for (int irow = 0; irow < cNRow; irow++) {
    9851136      if (!cBeams[beamCol[irow]-cBeam_1rel]) {
    9861137        sel[irow] = 0;
     
    9961147    if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow,
    9971148                      &IFNul, IFCol, &anynul, &cStatus)) {
    998       reportError();
    9991149      delete [] IFCol;
    10001150      delete [] sel;
     1151      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    10011152      return 1;
    10021153    }
    10031154
    1004     for (int irow = 0; irow < nRow; irow++) {
     1155    for (int irow = 0; irow < cNRow; irow++) {
    10051156      if (!cIFs[IFCol[irow]-cIF_1rel]) {
    10061157        sel[irow] = 0;
     
    10121163
    10131164  nSel = 0;
    1014   for (int irow = 0; irow < nRow; irow++) {
     1165  for (int irow = 0; irow < cNRow; irow++) {
    10151166    nSel += sel[irow];
    10161167  }
     
    10181169
    10191170  // Find the time range assuming the data is in chronological order.
    1020   readData(DATE_OBS, 1,    dateSpan[0]);
    1021   readData(DATE_OBS, nRow, dateSpan[1]);
    1022   readData(TIME, 1,    utcSpan);
    1023   readData(TIME, nRow, utcSpan+1);
    1024 
    1025   if (cALFA_BD) {
    1026     utcSpan[0] *= 3600.0;
    1027     utcSpan[1] *= 3600.0;
    1028   }
    1029 
    1030   // Check DATE-OBS format.
    1031   for (int i = 0; i < 2; i++) {
    1032     if (dateSpan[0][2] == '/') {
    1033       // Translate an old-format DATE-OBS.
    1034       dateSpan[i][9] = dateSpan[i][1];
    1035       dateSpan[i][8] = dateSpan[i][0];
    1036       dateSpan[i][2] = dateSpan[i][6];
    1037       dateSpan[i][5] = dateSpan[i][3];
    1038       dateSpan[i][3] = dateSpan[i][7];
    1039       dateSpan[i][6] = dateSpan[i][4];
    1040       dateSpan[i][7] = '-';
    1041       dateSpan[i][4] = '-';
    1042       dateSpan[i][1] = '9';
    1043       dateSpan[i][0] = '1';
    1044       dateSpan[i][10] = '\0';
    1045     }
    1046 
    1047     if (dateSpan[i][10] == 'T' && cData[TIME].colnum < 0) {
    1048       // Dig UTC out of a new-format DATE-OBS.
    1049       int   hh, mm;
    1050       float ss;
    1051       sscanf(dateSpan[i]+11, "%d:%d:%f", &hh, &mm, &ss);
    1052       utcSpan[i] = (hh*60 + mm)*60 + ss;
    1053     }
    1054   }
     1171  readTime(1, 1, dateSpan[0], utcSpan[0]);
     1172  readTime(cNRow, cNAxisTime, dateSpan[1], utcSpan[1]);
    10551173
    10561174
    10571175  // Retrieve positions for selected data.
    1058   double *ra  = new double[cNRow];
    1059   double *dec = new double[cNRow];
    1060   fits_read_col(cSDptr, TDOUBLE, cData[RA].colnum,  1, 1, nRow, 0, ra,
    1061                 &anynul, &cStatus);
    1062   fits_read_col(cSDptr, TDOUBLE, cData[DEC].colnum, 1, 1, nRow, 0, dec,
    1063                 &anynul, &cStatus);
    1064 
    1065   if (cALFA_BD) {
    1066     for (int irow = 0; irow < nRow; irow++) {
    1067       // Convert hours to degrees.
    1068       ra[irow] *= 15.0;
    1069     }
    1070   }
    1071 
    10721176  int isel = 0;
    10731177  positions = new double[2*nSel];
    10741178
    1075   // Parameters needed to compute feed-plane coordinates.
    1076   double *srcRA, *srcDec;
    1077   float  *par, *rot;
    1078   if (cGetFeedPos) {
    1079     srcRA  = new double[cNRow];
    1080     srcDec = new double[cNRow];
    1081     par    = new float[cNRow];
    1082     rot    = new float[cNRow];
    1083     fits_read_col(cSDptr, TDOUBLE, cData[OBJ_RA].colnum,   1, 1, nRow, 0,
    1084                   srcRA,  &anynul, &cStatus);
    1085     fits_read_col(cSDptr, TDOUBLE, cData[OBJ_DEC].colnum,  1, 1, nRow, 0,
    1086                   srcDec, &anynul, &cStatus);
    1087     fits_read_col(cSDptr, TFLOAT,  cData[PARANGLE].colnum, 1, 1, nRow, 0,
    1088                   par,    &anynul, &cStatus);
    1089     fits_read_col(cSDptr, TFLOAT,  cData[FOCUSROT].colnum, 1, 1, nRow, 0,
    1090                   rot,    &anynul, &cStatus);
    1091 
    1092     for (int irow = 0; irow < nRow; irow++) {
    1093       if (sel[irow]) {
    1094         // Convert to feed-plane coordinates.
    1095         Double dist, pa;
    1096         distPA(ra[irow]*D2R, dec[irow]*D2R, srcRA[irow]*D2R, srcDec[irow]*D2R,
    1097                dist, pa);
    1098 
    1099         Double spin = (par[irow] + rot[irow])*D2R - pa + PI;
    1100         if (spin > 2.0*PI) spin -= 2.0*PI;
    1101         Double squint = PI/2.0 - dist;
    1102 
    1103         positions[isel++] = spin;
    1104         positions[isel++] = squint;
    1105       }
    1106     }
    1107 
    1108     delete [] srcRA;
    1109     delete [] srcDec;
    1110     delete [] par;
    1111     delete [] rot;
     1179  if (cCoordSys == 1) {
     1180    // Horizontal (Az,El).
     1181    if (cData[AZIMUTH].colnum  < 0 ||
     1182        cData[ELEVATIO].colnum < 0) {
     1183      log(LogOrigin( className, methodName, WHERE ), LogIO::WARN, "Azimuth/elevation information absent.");
     1184      cStatus = -1;
     1185
     1186    } else {
     1187      float *az = new float[cNRow];
     1188      float *el = new float[cNRow];
     1189      readCol(AZIMUTH,  az);
     1190      readCol(ELEVATIO, el);
     1191
     1192      if (!cStatus) {
     1193        for (int irow = 0; irow < cNRow; irow++) {
     1194          if (sel[irow]) {
     1195            positions[isel++] = az[irow] * D2R;
     1196            positions[isel++] = el[irow] * D2R;
     1197          }
     1198        }
     1199      }
     1200
     1201      delete [] az;
     1202      delete [] el;
     1203    }
     1204
     1205  } else if (cCoordSys == 3) {
     1206    // ZPA-EL.
     1207    if (cData[BEAM].colnum < 0 ||
     1208        cData[FOCUSROT].colnum < 0 ||
     1209        cData[ELEVATIO].colnum < 0) {
     1210      log(LogOrigin( className, methodName, WHERE ), LogIO::WARN, "ZPA/elevation information absent.");
     1211      cStatus = -1;
     1212
     1213    } else {
     1214      short *beam = new short[cNRow];
     1215      float *rot  = new float[cNRow];
     1216      float *el   = new float[cNRow];
     1217      readCol(BEAM,     beam);
     1218      readCol(FOCUSROT, rot);
     1219      readCol(ELEVATIO, el);
     1220
     1221      if (!cStatus) {
     1222        for (int irow = 0; irow < cNRow; irow++) {
     1223          if (sel[irow]) {
     1224            Int beamNo = beam[irow];
     1225            Double zpa = rot[irow];
     1226            if (beamNo > 1) {
     1227              // Beam geometry for the Parkes multibeam.
     1228              if (beamNo < 8) {
     1229                zpa += -60.0 + 60.0*(beamNo-2);
     1230              } else {
     1231                zpa += -90.0 + 60.0*(beamNo-8);
     1232              }
     1233
     1234              if (zpa < -180.0) {
     1235                zpa += 360.0;
     1236              } else if (zpa > 180.0) {
     1237                zpa -= 360.0;
     1238              }
     1239            }
     1240
     1241            positions[isel++] = zpa * D2R;
     1242            positions[isel++] = el[irow] * D2R;
     1243          }
     1244        }
     1245      }
     1246
     1247      delete [] beam;
     1248      delete [] rot;
     1249      delete [] el;
     1250    }
    11121251
    11131252  } else {
    1114     for (int irow = 0; irow < nRow; irow++) {
    1115       if (sel[irow]) {
    1116         positions[isel++] =  ra[irow] * D2R;
    1117         positions[isel++] = dec[irow] * D2R;
    1118       }
    1119     }
    1120   }
    1121 
     1253    double *ra  = new double[cNRow];
     1254    double *dec = new double[cNRow];
     1255    readCol(RA,  ra);
     1256    readCol(DEC, dec);
     1257
     1258    if (cStatus) {
     1259      delete [] ra;
     1260      delete [] dec;
     1261      goto cleanup;
     1262    }
     1263
     1264    if (cALFA_BD) {
     1265      for (int irow = 0; irow < cNRow; irow++) {
     1266        // Convert hours to degrees.
     1267        ra[irow] *= 15.0;
     1268      }
     1269    }
     1270
     1271    if (cCoordSys == 0) {
     1272      // Equatorial (RA,Dec).
     1273      for (int irow = 0; irow < cNRow; irow++) {
     1274        if (sel[irow]) {
     1275          positions[isel++] =  ra[irow] * D2R;
     1276          positions[isel++] = dec[irow] * D2R;
     1277        }
     1278      }
     1279
     1280    } else if (cCoordSys == 2) {
     1281      // Feed-plane.
     1282      if (cData[OBJ_RA].colnum   < 0 ||
     1283          cData[OBJ_DEC].colnum  < 0 ||
     1284          cData[PARANGLE].colnum < 0 ||
     1285          cData[FOCUSROT].colnum < 0) {
     1286        log( LogOrigin( className, methodName, WHERE ), LogIO::WARN,
     1287             "Insufficient information to compute feed-plane\n"
     1288             "         coordinates.");
     1289        cStatus = -1;
     1290
     1291      } else {
     1292        double *srcRA  = new double[cNRow];
     1293        double *srcDec = new double[cNRow];
     1294        float  *par = new float[cNRow];
     1295        float  *rot = new float[cNRow];
     1296
     1297        readCol(OBJ_RA,   srcRA);
     1298        readCol(OBJ_DEC,  srcDec);
     1299        readCol(PARANGLE, par);
     1300        readCol(FOCUSROT, rot);
     1301
     1302        if (!cStatus) {
     1303          for (int irow = 0; irow < cNRow; irow++) {
     1304            if (sel[irow]) {
     1305              // Convert to feed-plane coordinates.
     1306              Double dist, pa;
     1307              distPA(ra[irow]*D2R, dec[irow]*D2R, srcRA[irow]*D2R,
     1308                     srcDec[irow]*D2R, dist, pa);
     1309
     1310              Double spin = (par[irow] + rot[irow])*D2R - pa;
     1311              if (spin > 2.0*PI) spin -= 2.0*PI;
     1312              Double squint = PI/2.0 - dist;
     1313
     1314              positions[isel++] = spin;
     1315              positions[isel++] = squint;
     1316            }
     1317          }
     1318        }
     1319
     1320        delete [] srcRA;
     1321        delete [] srcDec;
     1322        delete [] par;
     1323        delete [] rot;
     1324      }
     1325    }
     1326
     1327    delete [] ra;
     1328    delete [] dec;
     1329  }
     1330
     1331cleanup:
    11221332  delete [] sel;
    1123   delete [] ra;
    1124   delete [] dec;
    1125 
    1126   return cStatus;
     1333
     1334  if (cStatus) {
     1335    nSel = 0;
     1336    delete [] positions;
     1337    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
     1338    cStatus = 0;
     1339    return 1;
     1340  }
     1341
     1342  return 0;
    11271343}
    11281344
     
    11331349
    11341350int SDFITSreader::read(
    1135         PKSMBrecord &mbrec)
     1351        MBrecord &mbrec)
    11361352{
     1353  const string methodName = "read()" ;
     1354
    11371355  // Has the file been opened?
    11381356  if (!cSDptr) {
    11391357    return 1;
    11401358  }
    1141 
    11421359  // Find the next selected beam and IF.
    11431360  short iBeam = 0, iIF = 0;
    1144   while (++cRow <= cNRow) {
     1361  int iPol = -1 ;
     1362  while (1) {
     1363    if (++cTimeIdx > cNAxisTime) {
     1364      if (++cRow > cNRow) break;
     1365      cTimeIdx = 1;
     1366    }
     1367
    11451368    if (cData[BEAM].colnum > 0) {
    11461369      readData(BEAM, cRow, &iBeam);
     
    11641387          char chars[32];
    11651388          readData(OBSMODE, cRow, chars);
    1166           if (strcmp(chars, "CAL") == 0) {
    1167             // iIF is really the polarization in ALFA data.
    1168             alfaCal(iBeam, iIF);
     1389          if (strcmp(chars, "DROP") == 0) {
     1390            // Completely flagged integration.
    11691391            continue;
     1392
     1393          } else if (strcmp(chars, "CAL") == 0) {
     1394            sReset = 1;
     1395            if (cALFA_CIMA > 1) {
     1396              for (short iPol = 0; iPol < cNPol[iIF]; iPol++) {
     1397                alfaCal(iBeam, iIF, iPol);
     1398              }
     1399              continue;
     1400            } else {
     1401              // iIF is really the polarization in older ALFA data.
     1402              alfaCal(iBeam, 0, iIF);
     1403              continue;
     1404            }
     1405
     1406          } else {
     1407            // Reset for the next CAL record.
     1408            if (sReset) {
     1409              for (short iPol = 0; iPol < cNPol[iIF]; iPol++) {
     1410                sALFAcalNon[iBeam][iPol]  = 0;
     1411                sALFAcalNoff[iBeam][iPol] = 0;
     1412                sALFAcalOn[iBeam][iPol]   = 0.0f;
     1413                sALFAcalOff[iBeam][iPol]  = 0.0f;
     1414              }
     1415              sReset = 0;
     1416
     1417              sprintf(cMsg, "ALFA cal factors for beam %d: %.3e, %.3e",
     1418                iBeam+1, sALFAcal[iBeam][0], sALFAcal[iBeam][1]);
     1419              log(LogOrigin( className, methodName, WHERE ), LogIO::NORMAL, cMsg);
     1420              //logMsg(cMsg);
     1421            }
    11701422          }
    11711423        }
    11721424
     1425        // for GBT SDFITS
     1426        if (cData[STOKES].colnum > 0 ) {
     1427          readData(STOKES, cRow, &iPol ) ;
     1428          for ( int i = 0 ; i < cNPol[iIF] ; i++ ) {
     1429            if ( cPols[i] == iPol ) {
     1430              iPol = i ;
     1431              break ;
     1432            }
     1433          }
     1434        }
    11731435        break;
    11741436      }
     
    12001462  // Times.
    12011463  char datobs[32];
    1202   readData(DATE_OBS, cRow,  datobs);
    1203   readData(TIME,     cRow, &mbrec.utc);
    1204   if (cALFA_BD) mbrec.utc *= 3600.0;
    1205 
    1206   if (datobs[2] == '/') {
    1207     // Translate an old-format DATE-OBS.
    1208     datobs[9] = datobs[1];
    1209     datobs[8] = datobs[0];
    1210     datobs[2] = datobs[6];
    1211     datobs[5] = datobs[3];
    1212     datobs[3] = datobs[7];
    1213     datobs[6] = datobs[4];
    1214     datobs[7] = '-';
    1215     datobs[4] = '-';
    1216     datobs[1] = '9';
    1217     datobs[0] = '1';
    1218 
    1219   } else if (datobs[10] == 'T' && cData[TIME].colnum < 0) {
    1220     // Dig UTC out of a new-format DATE-OBS.
    1221     int   hh, mm;
    1222     float ss;
    1223     sscanf(datobs+11, "%d:%d:%f", &hh, &mm, &ss);
    1224     mbrec.utc = (hh*60 + mm)*60 + ss;
    1225   }
    1226 
    1227   datobs[10] = '\0';
     1464  readTime(cRow, cTimeIdx, datobs, mbrec.utc);
    12281465  strcpy(mbrec.datobs, datobs);
    12291466
    12301467  if (cData[CYCLE].colnum > 0) {
    12311468    readData(CYCLE, cRow, &mbrec.cycleNo);
     1469    mbrec.cycleNo += cTimeIdx - 1;
    12321470    if (cALFA_BD) mbrec.cycleNo++;
    12331471  } else {
     
    12391477  }
    12401478
     1479  if ( iPol != -1 ) {
     1480    if ( mbrec.scanNo != cGLastScan[iPol] ) {
     1481      cGLastScan[iPol] = mbrec.scanNo ;
     1482      cGCycleNo[iPol] = 0 ;
     1483      mbrec.cycleNo = ++cGCycleNo[iPol] ;
     1484    }
     1485    else {
     1486      mbrec.cycleNo = ++cGCycleNo[iPol] ;
     1487    }
     1488  }
     1489
    12411490  readData(EXPOSURE, cRow, &mbrec.exposure);
    12421491
    12431492  // Source identification.
    1244   readData(OBJECT,  cRow,  mbrec.srcName);
     1493  readData(OBJECT, cRow, mbrec.srcName);
     1494
     1495  if ( iPol != -1 ) {
     1496    char obsmode[32] ;
     1497    readData( OBSMODE, cRow, obsmode ) ;
     1498    char sig[1] ;
     1499    char cal[1] ;
     1500    readData( SIG, cRow, sig ) ;
     1501    readData( CAL, cRow, cal ) ;
     1502    if ( strstr( obsmode, "PSWITCH" ) != NULL ) {
     1503      // position switch
     1504      strcat( mbrec.srcName, "_p" ) ;
     1505      if ( strstr( obsmode, "PSWITCHON" ) != NULL ) {
     1506        strcat( mbrec.srcName, "s" ) ;
     1507      }
     1508      else if ( strstr( obsmode, "PSWITCHOFF" ) != NULL ) {
     1509        strcat( mbrec.srcName, "r" ) ;
     1510      }
     1511    }
     1512    else if ( strstr( obsmode, "Nod" ) != NULL ) {
     1513      // nod
     1514      strcat( mbrec.srcName, "_n" ) ;
     1515      if ( sig[0] == 'T' ) {
     1516        strcat( mbrec.srcName, "s" ) ;
     1517      }
     1518      else {
     1519        strcat( mbrec.srcName, "r" ) ;
     1520      }
     1521    }
     1522    else if ( strstr( obsmode, "FSWITCH" ) != NULL ) {
     1523      // frequency switch
     1524      strcat( mbrec.srcName, "_f" ) ;
     1525      if ( sig[0] == 'T' ) {
     1526        strcat( mbrec.srcName, "s" ) ;
     1527      }
     1528      else {
     1529        strcat( mbrec.srcName, "r" ) ;
     1530      }
     1531    }
     1532    if ( cal[0] == 'T' ) {
     1533      strcat( mbrec.srcName, "c" ) ;
     1534    }
     1535    else {
     1536      strcat( mbrec.srcName, "o" ) ;
     1537    }
     1538  }
    12451539
    12461540  readData(OBJ_RA,  cRow, &mbrec.srcRA);
     
    12791573    mbrec.decRate = scanrate[1] * D2R;
    12801574  }
     1575  mbrec.paRate = 0.0f;
    12811576
    12821577  // IF-dependent parameters.
     
    12891584  int nPol = cNPol[iIF];
    12901585
     1586  if ( cData[STOKES].colnum > 0 )
     1587    nPol = 1 ;
     1588
    12911589  if (cGetSpectra || cGetXPol) {
    12921590    int nxpol = cGetXPol ? 2*nChan : 0;
     
    12981596  mbrec.nChan[0] = nChan;
    12991597  mbrec.nPol[0]  = nPol;
     1598  mbrec.polNo = iPol ;
    13001599
    13011600  readData(FqRefPix, cRow, mbrec.fqRefPix);
     
    13161615
    13171616  if (cStatus) {
    1318     reportError();
     1617    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    13191618    return 1;
    13201619  }
     
    13531652
    13541653  if (cStatus) {
    1355     reportError();
     1654    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    13561655    return 1;
    13571656  }
    13581657
    13591658  // Read data, sectioning and transposing it in the process.
    1360   long *blc = new long[cNAxis+1];
    1361   long *trc = new long[cNAxis+1];
    1362   long *inc = new long[cNAxis+1];
    1363   for (int iaxis = 0; iaxis <= cNAxis; iaxis++) {
     1659  long *blc = new long[cNAxes+1];
     1660  long *trc = new long[cNAxes+1];
     1661  long *inc = new long[cNAxes+1];
     1662  for (int iaxis = 0; iaxis <= cNAxes; iaxis++) {
    13641663    blc[iaxis] = 1;
    13651664    trc[iaxis] = 1;
     
    13671666  }
    13681667
    1369   blc[cReqax[0]] = std::min(startChan, endChan);
    1370   trc[cReqax[0]] = std::max(startChan, endChan);
    1371   blc[cNAxis] = cRow;
    1372   trc[cNAxis] = cRow;
     1668  blc[cFreqAxis] = std::min(startChan, endChan);
     1669  trc[cFreqAxis] = std::max(startChan, endChan);
     1670  if (cTimeAxis >= 0) {
     1671    blc[cTimeAxis] = cTimeIdx;
     1672    trc[cTimeAxis] = cTimeIdx;
     1673  }
     1674  blc[cNAxes] = cRow;
     1675  trc[cNAxes] = cRow;
    13731676
    13741677  mbrec.haveSpectra = cGetSpectra;
     
    13761679    int  anynul;
    13771680
    1378     for (int ipol = 0; ipol < nPol; ipol++) {
    1379       blc[cReqax[1]] = ipol+1;
    1380       trc[cReqax[1]] = ipol+1;
    1381 
    1382       if (cALFA) {
     1681    for (int iPol = 0; iPol < nPol; iPol++) {
     1682      blc[cStokesAxis] = iPol+1;
     1683      trc[cStokesAxis] = iPol+1;
     1684
     1685      if (cALFA && cALFA_CIMA < 2) {
    13831686        // ALFA data: polarizations are stored in successive rows.
    1384         blc[cReqax[1]] = 1;
    1385         trc[cReqax[1]] = 1;
    1386 
    1387         if (ipol) {
     1687        blc[cStokesAxis] = 1;
     1688        trc[cStokesAxis] = 1;
     1689
     1690        if (iPol) {
    13881691          if (++cRow > cNRow) {
    13891692            return -1;
    13901693          }
    13911694
    1392           blc[cNAxis] = cRow;
    1393           trc[cNAxis] = cRow;
     1695          blc[cNAxes] = cRow;
     1696          trc[cNAxes] = cRow;
    13941697        }
    13951698
    13961699      } else if (cData[DATA].nelem < 0) {
    13971700        // Variable dimension array; get axis lengths.
    1398         int  naxis = 5, status;
    1399 
    1400         if ((status = readDim(DATA, cRow, &naxis, cNAxes))) {
    1401           reportError();
    1402 
    1403         } else if ((status = (naxis != cNAxis))) {
    1404           cerr << "DATA array dimensions changed." << endl;
     1701        int naxes = 5, status;
     1702
     1703        if ((status = readDim(DATA, cRow, &naxes, cNAxis))) {
     1704          log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
     1705
     1706        } else if ((status = (naxes != cNAxes))) {
     1707          log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "DATA array dimensions changed.");
    14051708        }
    14061709
     
    14131716      }
    14141717
    1415       if (fits_read_subset_flt(cSDptr, cData[DATA].colnum, cNAxis, cNAxes,
    1416           blc, trc, inc, 0, mbrec.spectra[0] + ipol*nChan, &anynul,
     1718      if (fits_read_subset_flt(cSDptr, cData[DATA].colnum, cNAxes, cNAxis,
     1719          blc, trc, inc, 0, mbrec.spectra[0] + iPol*nChan, &anynul,
    14171720          &cStatus)) {
    1418         reportError();
     1721        log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    14191722        delete [] blc;
    14201723        delete [] trc;
     
    14251728      if (endChan < startChan) {
    14261729        // Reverse the spectrum.
    1427         float *iptr = mbrec.spectra[0] + ipol*nChan;
     1730        float *iptr = mbrec.spectra[0] + iPol*nChan;
    14281731        float *jptr = iptr + nChan - 1;
    14291732        float *mid  = iptr + nChan/2;
     
    14371740      if (cALFA) {
    14381741        // ALFA data, rescale the spectrum.
    1439         float *chan  = mbrec.spectra[0] + ipol*nChan;
     1742        float el, zd;
     1743        readData(ELEVATIO, cRow, &el);
     1744        zd = 90.0f - el;
     1745
     1746        float factor = sALFAcal[iBeam][iPol] / alfaGain(zd);
     1747
     1748        if (cALFA_CIMA > 1) {
     1749          // Rescale according to the number of unblanked accumulations.
     1750          int colnum, naccum;
     1751          findCol("STAT", &colnum);
     1752          fits_read_col(cSDptr, TINT, colnum, cRow, 10*(cTimeIdx-1)+2, 1, 0,
     1753                        &naccum, &anynul, &cStatus);
     1754          factor *= cALFAacc / naccum;
     1755        }
     1756
     1757        float *chan  = mbrec.spectra[0] + iPol*nChan;
    14401758        float *chanN = chan + nChan;
    14411759        while (chan < chanN) {
    14421760          // Approximate conversion to Jy.
    1443           *(chan++) *= cALFAcal[iBeam][iIF];
     1761          *(chan++) *= factor;
    14441762        }
    14451763      }
    14461764
    1447       if (mbrec.tsys[0][ipol] == 0.0) {
     1765      if (mbrec.tsys[0][iPol] == 0.0) {
    14481766        // Compute Tsys as the average across the spectrum.
    1449         float *chan  = mbrec.spectra[0] + ipol*nChan;
     1767        float *chan  = mbrec.spectra[0] + iPol*nChan;
    14501768        float *chanN = chan + nChan;
    1451         float *tsys = mbrec.tsys[0] + ipol;
     1769        float *tsys = mbrec.tsys[0] + iPol;
    14521770        while (chan < chanN) {
    14531771          *tsys += *(chan++);
     
    14591777      // Read data flags.
    14601778      if (cData[FLAGGED].colnum > 0) {
    1461         if (fits_read_subset_byt(cSDptr, cData[FLAGGED].colnum, cNAxis,
    1462             cNAxes, blc, trc, inc, 0, mbrec.flagged[0] + ipol*nChan, &anynul,
     1779        if (fits_read_subset_byt(cSDptr, cData[FLAGGED].colnum, cNAxes,
     1780            cNAxis, blc, trc, inc, 0, mbrec.flagged[0] + iPol*nChan, &anynul,
    14631781            &cStatus)) {
    1464           reportError();
     1782          log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    14651783          delete [] blc;
    14661784          delete [] trc;
     
    14711789        if (endChan < startChan) {
    14721790          // Reverse the flag vector.
    1473           unsigned char *iptr = mbrec.flagged[0] + ipol*nChan;
     1791          unsigned char *iptr = mbrec.flagged[0] + iPol*nChan;
    14741792          unsigned char *jptr = iptr + nChan - 1;
    14751793          for (int ichan = 0; ichan < nChan/2; ichan++) {
     
    14821800      } else {
    14831801        // All channels are unflagged by default.
    1484         unsigned char *iptr = mbrec.flagged[0] + ipol*nChan;
     1802        unsigned char *iptr = mbrec.flagged[0] + iPol*nChan;
    14851803        for (int ichan = 0; ichan < nChan; ichan++) {
    14861804          *(iptr++) = 0;
     
    15131831    if (fits_read_subset_flt(cSDptr, cData[XPOLDATA].colnum, nAxis, nAxes,
    15141832        blc, trc, inc, 0, mbrec.xpol[0], &anynul, &cStatus)) {
    1515       reportError();
     1833      log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    15161834      delete [] blc;
    15171835      delete [] trc;
     
    15441862
    15451863  if (cStatus) {
    1546     reportError();
     1864    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    15471865    return 1;
    15481866  }
     
    15521870  readData(TCAL,     cRow, &mbrec.tcal[0]);
    15531871  readData(TCALTIME, cRow,  mbrec.tcalTime);
     1872
    15541873  readData(AZIMUTH,  cRow, &mbrec.azimuth);
    15551874  readData(ELEVATIO, cRow, &mbrec.elevation);
    15561875  readData(PARANGLE, cRow, &mbrec.parAngle);
     1876
    15571877  readData(FOCUSAXI, cRow, &mbrec.focusAxi);
    15581878  readData(FOCUSTAN, cRow, &mbrec.focusTan);
    15591879  readData(FOCUSROT, cRow, &mbrec.focusRot);
     1880
    15601881  readData(TAMBIENT, cRow, &mbrec.temp);
    15611882  readData(PRESSURE, cRow, &mbrec.pressure);
     
    15751896  mbrec.windAz    *= D2R;
    15761897
     1898  // For GBT data, source velocity can be evaluated
     1899  if ( cData[RVSYS].colnum > 0 && cData[VFRAME].colnum > 0 ) {
     1900    float vframe;
     1901    readData(VFRAME, cRow, &vframe);
     1902    float rvsys;
     1903    readData(RVSYS,  cRow, &rvsys);
     1904    //mbrec.srcVelocity = rvsys - vframe ;
     1905    mbrec.srcVelocity = rvsys ;
     1906  }
     1907
    15771908  if (cStatus) {
    1578     reportError();
     1909    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
    15791910    return 1;
    15801911  }
    15811912
    15821913  return 0;
    1583 }
    1584 
    1585 
    1586 //------------------------------------------------------ SDFITSreader::alfaCal
    1587 
    1588 // Process ALFA calibration data.
    1589 
    1590 int SDFITSreader::alfaCal(
    1591         short iBeam,
    1592         short iPol)
    1593 {
    1594   int  calOn;
    1595   char chars[32];
    1596   if (cALFA_BD) {
    1597     readData("OBS_NAME", TSTRING, cRow, chars);
    1598   } else {
    1599     readData("SCANTYPE", TSTRING, cRow, chars);
    1600   }
    1601 
    1602   if (strcmp(chars, "ON") == 0) {
    1603     calOn = 1;
    1604   } else if (strcmp(chars, "OFF") == 0) {
    1605     calOn = 0;
    1606   } else {
    1607     return 1;
    1608   }
    1609 
    1610   // Read cal data.
    1611   long *blc = new long[cNAxis+1];
    1612   long *trc = new long[cNAxis+1];
    1613   long *inc = new long[cNAxis+1];
    1614   for (int iaxis = 0; iaxis <= cNAxis; iaxis++) {
    1615     blc[iaxis] = 1;
    1616     trc[iaxis] = 1;
    1617     inc[iaxis] = 1;
    1618   }
    1619 
    1620   // User channel selection.
    1621   int startChan = cStartChan[0];
    1622   int endChan   = cEndChan[0];
    1623 
    1624   blc[cNAxis] = cRow;
    1625   trc[cNAxis] = cRow;
    1626   blc[cReqax[0]] = std::min(startChan, endChan);
    1627   trc[cReqax[0]] = std::max(startChan, endChan);
    1628   blc[cReqax[1]] = 1;
    1629   trc[cReqax[1]] = 1;
    1630 
    1631   float spectrum[endChan];
    1632   int anynul;
    1633   if (fits_read_subset_flt(cSDptr, cData[DATA].colnum, cNAxis, cNAxes,
    1634       blc, trc, inc, 0, spectrum, &anynul, &cStatus)) {
    1635     reportError();
    1636     delete [] blc;
    1637     delete [] trc;
    1638     delete [] inc;
    1639     return 1;
    1640   }
    1641 
    1642   // Average the spectrum.
    1643   float mean = 1e9f;
    1644   for (int k = 0; k < 2; k++) {
    1645     float discrim = 2.0f * mean;
    1646 
    1647     int nChan = 0;
    1648     float sum = 0.0f;
    1649 
    1650     float *chanN = spectrum + abs(endChan - startChan) + 1;
    1651     for (float *chan = spectrum; chan < chanN; chan++) {
    1652       // Simple discriminant that eliminates strong radar interference.
    1653       if (*chan < discrim) {
    1654         nChan++;
    1655         sum += *chan;
    1656       }
    1657     }
    1658 
    1659     mean = sum / nChan;
    1660   }
    1661 
    1662   if (calOn) {
    1663     cALFAcalOn[iBeam][iPol]  += mean;
    1664   } else {
    1665     cALFAcalOff[iBeam][iPol] += mean;
    1666   }
    1667 
    1668   if (cALFAcalOn[iBeam][iPol] != 0.0f &&
    1669       cALFAcalOff[iBeam][iPol] != 0.0f) {
    1670     // Tcal should come from the TCAL table, it varies weakly with beam,
    1671     // polarization, and frequency.  However, TCAL is not written properly.
    1672     float Tcal = 12.0f;
    1673     cALFAcal[iBeam][iPol] = Tcal / (cALFAcalOn[iBeam][iPol] -
    1674                                     cALFAcalOff[iBeam][iPol]);
    1675 
    1676     // Scale from K to Jy; the gain also varies weakly with beam,
    1677     // polarization, frequency, and zenith angle.
    1678     float fluxCal = 10.0f;
    1679     cALFAcal[iBeam][iPol] /= fluxCal;
    1680 
    1681     cALFAcalOn[iBeam][iPol]  = 0.0f;
    1682     cALFAcalOff[iBeam][iPol] = 0.0f;
    1683   }
    1684 
    1685   return 0;
    1686 }
    1687 
    1688 
    1689 //-------------------------------------------------- SDFITSreader::reportError
    1690 
    1691 // Print the error message corresponding to the input status value and all the
    1692 // messages on the CFITSIO error stack to stderr.
    1693 
    1694 void SDFITSreader::reportError()
    1695 {
    1696   fits_report_error(stderr, cStatus);
    16971914}
    16981915
     
    17061923    int status = 0;
    17071924    fits_close_file(cSDptr, &status);
    1708     cSDptr = 0;
     1925    cSDptr = 0x0;
    17091926
    17101927    if (cBeams)     delete [] cBeams;
     
    17141931    if (cRefChan)   delete [] cRefChan;
    17151932  }
     1933}
     1934
     1935//------------------------------------------------------- SDFITSreader::log
     1936
     1937// Log a message.  If the current CFITSIO status value is non-zero, also log
     1938// the corresponding error message and the CFITSIO message stack.
     1939
     1940void SDFITSreader::log(LogOrigin origin, LogIO::Command cmd, const char *msg)
     1941{
     1942  LogIO os( origin ) ;
     1943
     1944  os << msg << endl ;
     1945
     1946  if (cStatus > 0) {
     1947    fits_get_errstatus(cStatus, cMsg);
     1948    os << cMsg << endl ;
     1949
     1950    while (fits_read_errmsg(cMsg)) {
     1951      os << cMsg << endl ;
     1952    }
     1953  }
     1954  os << LogIO::POST ;
    17161955}
    17171956
     
    17371976    long nelem, width;
    17381977    fits_get_coltype(cSDptr, colnum, &coltype, &nelem, &width, &cStatus);
     1978    fits_get_bcolparms(cSDptr, colnum, 0x0, cData[iData].units, 0x0, 0x0, 0x0,
     1979      0x0, 0x0, 0x0, &cStatus);
    17391980
    17401981    // Look for a TDIMnnn keyword or column.
     
    17682009}
    17692010
     2011//------------------------------------------------------ SDFITSreader::findCol
     2012
     2013// Locate a parameter in the SDFITS file.
     2014
     2015void SDFITSreader::findCol(
     2016        char *name,
     2017        int *colnum)
     2018{
     2019  *colnum = 0;
     2020  int status = 0;
     2021  fits_get_colnum(cSDptr, CASESEN, name, colnum, &status);
     2022
     2023  if (status) {
     2024    // Not a real column - maybe it's virtual.
     2025    char card[81];
     2026
     2027    status = 0;
     2028    fits_read_card(cSDptr, name, card, &status);
     2029    if (status) {
     2030      // Not virtual either.
     2031      *colnum = -1;
     2032    }
     2033
     2034    // Clear error messages.
     2035    fits_clear_errmsg();
     2036  }
     2037}
     2038
    17702039//------------------------------------------------------ SDFITSreader::readDim
    17712040
     
    17752044        int  iData,
    17762045        long iRow,
    1777         int *naxis,
    1778         long naxes[])
     2046        int *naxes,
     2047        long naxis[])
    17792048{
    17802049  int colnum = cData[iData].colnum;
     
    17832052  }
    17842053
    1785   int maxdim = *naxis;
     2054  int maxdim = *naxes;
    17862055  if (cData[iData].tdimcol < 0) {
    17872056    // No TDIMnnn column for this array.
    17882057    if (cData[iData].nelem < 0) {
    17892058      // Variable length array; read the array descriptor.
    1790       *naxis = 1;
     2059      *naxes = 1;
    17912060      long dummy;
    1792       if (fits_read_descript(cSDptr, colnum, iRow, naxes, &dummy, &cStatus)) {
     2061      if (fits_read_descript(cSDptr, colnum, iRow, naxis, &dummy, &cStatus)) {
    17932062        return 1;
    17942063      }
     
    17962065    } else {
    17972066      // Read the repeat count from TFORMnnn.
    1798       if (fits_read_tdim(cSDptr, colnum, maxdim, naxis, naxes, &cStatus)) {
     2067      if (fits_read_tdim(cSDptr, colnum, maxdim, naxes, naxis, &cStatus)) {
    17992068        return 1;
    18002069      }
     
    18142083
    18152084    tp++;
    1816     *naxis = 0;
     2085    *naxes = 0;
    18172086    for (size_t j = 1; j < strlen(tdimval); j++) {
    18182087      if (tdimval[j] == ',' || tdimval[j] == ')') {
    1819         sscanf(tp, "%ld", naxes + (*naxis)++);
     2088        sscanf(tp, "%ld", naxis + (*naxes)++);
    18202089        if (tdimval[j] == ')') break;
    18212090        tp = tdimval + j + 1;
     
    18522121  findCol(name, &colnum);
    18532122
    1854   if (colnum > 0) {
     2123  if (colnum > 0 && iRow > 0) {
    18552124    // Read the first value from the specified row of the table.
    18562125    int  coltype;
     
    19152184        void *value)
    19162185{
    1917   char *name  = cData[iData].name;
    19182186  int  type   = cData[iData].type;
    19192187  int  colnum = cData[iData].colnum;
    1920   long nelem  = cData[iData].nelem;
    1921 
    1922   if (colnum > 0) {
     2188
     2189  if (colnum > 0 && iRow > 0) {
    19232190    // Read the required number of values from the specified row of the table.
     2191    long nelem = cData[iData].nelem;
    19242192    int anynul;
    19252193    if (type == TSTRING) {
     
    19502218  } else if (colnum == 0) {
    19512219    // Read keyword value.
     2220    char *name  = cData[iData].name;
    19522221    fits_read_key(cSDptr, type, name, value, 0, &cStatus);
    19532222
     
    19702239}
    19712240
    1972 //------------------------------------------------------ SDFITSreader::findCol
    1973 
    1974 // Locate a parameter in the SDFITS file.
    1975 
    1976 void SDFITSreader::findCol(
    1977         char *name,
    1978         int *colnum)
     2241//------------------------------------------------------ SDFITSreader::readCol
     2242
     2243// Read a scalar column from the SDFITS file.
     2244
     2245int SDFITSreader::readCol(
     2246        int  iData,
     2247        void *value)
    19792248{
    1980   *colnum = 0;
    1981   int status = 0;
    1982   fits_get_colnum(cSDptr, CASESEN, name, colnum, &status);
    1983 
    1984   if (status) {
    1985     // Not a real column - maybe it's virtual.
    1986     char card[81];
    1987 
    1988     status = 0;
    1989     fits_read_card(cSDptr, name, card, &status);
    1990     if (status) {
    1991       // Not virtual either.
    1992       *colnum = -1;
    1993     }
    1994 
    1995     // Clear error messages.
    1996     fits_clear_errmsg();
    1997   }
     2249  int type = cData[iData].type;
     2250
     2251  if (cData[iData].colnum > 0) {
     2252    // Table column.
     2253    int anynul;
     2254    fits_read_col(cSDptr, type, cData[iData].colnum, 1, 1, cNRow, 0,
     2255                  value, &anynul, &cStatus);
     2256
     2257  } else {
     2258    // Header keyword.
     2259    readData(iData, 0, value);
     2260    for (int irow = 1; irow < cNRow; irow++) {
     2261      if (type == TSHORT) {
     2262        ((short *)value)[irow] = *((short *)value);
     2263      } else if (type == TINT) {
     2264        ((int *)value)[irow] = *((int *)value);
     2265      } else if (type == TFLOAT) {
     2266        ((float *)value)[irow] = *((float *)value);
     2267      } else if (type == TDOUBLE) {
     2268        ((double *)value)[irow] = *((double *)value);
     2269      }
     2270    }
     2271  }
     2272
     2273  return cData[iData].colnum < 0;
    19982274}
     2275
     2276//----------------------------------------------------- SDFITSreader::readTime
     2277
     2278// Read the time from the SDFITS file.
     2279
     2280int SDFITSreader::readTime(
     2281        long iRow,
     2282        int  iPix,
     2283        char   *datobs,
     2284        double &utc)
     2285{
     2286  readData(DATE_OBS, iRow, datobs);
     2287  if (cData[TIME].colnum >= 0) {
     2288    readData(TIME, iRow, &utc);
     2289  } else if (cGBT) {
     2290    Int yy, mm ;
     2291    Double dd, hour, min, sec ;
     2292    sscanf( datobs, "%d-%d-%lfT%lf:%lf:%lf", &yy, &mm, &dd, &hour, &min, &sec ) ;
     2293    dd = dd + ( hour * 3600.0 + min * 60.0 + sec ) / 86400.0 ;
     2294    MVTime mvt( yy, mm, dd ) ;
     2295    dd = mvt.day() ;
     2296    utc = fmod( dd, 1.0 ) * 86400.0 ;
     2297  } else if (cNAxisTime > 1) {
     2298    double timeDelt, timeRefPix, timeRefVal;
     2299    readData(TimeRefVal, iRow, &timeRefVal);
     2300    readData(TimeDelt,   iRow, &timeDelt);
     2301    readData(TimeRefPix, iRow, &timeRefPix);
     2302    utc = timeRefVal + (iPix - timeRefPix) * timeDelt;
     2303  }
     2304
     2305  if (cALFA_BD) utc *= 3600.0;
     2306
     2307  // Check DATE-OBS format.
     2308  if (datobs[2] == '/') {
     2309    // Translate an old-format DATE-OBS.
     2310    datobs[9] = datobs[1];
     2311    datobs[8] = datobs[0];
     2312    datobs[2] = datobs[6];
     2313    datobs[5] = datobs[3];
     2314    datobs[3] = datobs[7];
     2315    datobs[6] = datobs[4];
     2316    datobs[7] = '-';
     2317    datobs[4] = '-';
     2318    datobs[1] = '9';
     2319    datobs[0] = '1';
     2320
     2321  } else if (datobs[10] == 'T' && cData[TIME].colnum < 0) {
     2322    // Dig UTC out of a new-format DATE-OBS.
     2323    int   hh, mm;
     2324    float ss;
     2325    sscanf(datobs+11, "%d:%d:%f", &hh, &mm, &ss);
     2326    utc = (hh*60 + mm)*60 + ss;
     2327  }
     2328
     2329  datobs[10] = '\0';
     2330
     2331  return 0;
     2332}
     2333
     2334//------------------------------------------------------ SDFITSreader::alfaCal
     2335
     2336// Process ALFA calibration data.
     2337
     2338int SDFITSreader::alfaCal(
     2339        short iBeam,
     2340        short iIF,
     2341        short iPol)
     2342{
     2343  const string methodName = "alfaCal()" ;
     2344
     2345  int  calOn;
     2346  char chars[32];
     2347  if (cALFA_BD) {
     2348    readData("OBS_NAME", TSTRING, cRow, chars);
     2349  } else {
     2350    readData("SCANTYPE", TSTRING, cRow, chars);
     2351  }
     2352
     2353  if (strcmp(chars, "ON") == 0) {
     2354    calOn = 1;
     2355  } else if (strcmp(chars, "OFF") == 0) {
     2356    calOn = 0;
     2357  } else {
     2358    return 1;
     2359  }
     2360
     2361  // Read cal data.
     2362  long *blc = new long[cNAxes+1];
     2363  long *trc = new long[cNAxes+1];
     2364  long *inc = new long[cNAxes+1];
     2365  for (int iaxis = 0; iaxis <= cNAxes; iaxis++) {
     2366    blc[iaxis] = 1;
     2367    trc[iaxis] = 1;
     2368    inc[iaxis] = 1;
     2369  }
     2370
     2371  // User channel selection.
     2372  int startChan = cStartChan[iIF];
     2373  int endChan   = cEndChan[iIF];
     2374
     2375  blc[cFreqAxis] = std::min(startChan, endChan);
     2376  trc[cFreqAxis] = std::max(startChan, endChan);
     2377  if (cALFA_CIMA > 1) {
     2378    // CIMAFITS 2.x has a legitimate STOKES axis...
     2379    blc[cStokesAxis] = iPol+1;
     2380    trc[cStokesAxis] = iPol+1;
     2381  } else {
     2382    // ...older ALFA data does not.
     2383    blc[cStokesAxis] = 1;
     2384    trc[cStokesAxis] = 1;
     2385  }
     2386  if (cTimeAxis >= 0) {
     2387    blc[cTimeAxis] = cTimeIdx;
     2388    trc[cTimeAxis] = cTimeIdx;
     2389  }
     2390  blc[cNAxes] = cRow;
     2391  trc[cNAxes] = cRow;
     2392
     2393  float spectrum[endChan];
     2394  int anynul;
     2395  if (fits_read_subset_flt(cSDptr, cData[DATA].colnum, cNAxes, cNAxis,
     2396      blc, trc, inc, 0, spectrum, &anynul, &cStatus)) {
     2397    log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE);
     2398    delete [] blc;
     2399    delete [] trc;
     2400    delete [] inc;
     2401    return 1;
     2402  }
     2403
     2404  // Factor to rescale according to the number of unblanked accumulations.
     2405  float factor = 1.0f;
     2406  if (cALFA_CIMA > 1) {
     2407    int   colnum, naccum;
     2408    findCol("STAT", &colnum);
     2409    fits_read_col(cSDptr, TINT, colnum, cRow, 2, 1, 0, &naccum, &anynul,
     2410                  &cStatus);
     2411    factor = cALFAacc / naccum;
     2412  }
     2413
     2414  // Average the spectrum.
     2415  float mean = 1e9f;
     2416  for (int k = 0; k < 2; k++) {
     2417    float discrim = 2.0f * mean;
     2418
     2419    int nChan = 0;
     2420    float sum = 0.0f;
     2421
     2422    float *chanN = spectrum + abs(endChan - startChan) + 1;
     2423    for (float *chan = spectrum; chan < chanN; chan++) {
     2424      // Simple discriminant that eliminates strong radar interference.
     2425      if (*chan < discrim) {
     2426        nChan++;
     2427        sum += *chan * factor;
     2428      }
     2429    }
     2430
     2431    mean = sum / nChan;
     2432  }
     2433
     2434  if (calOn) {
     2435    sALFAcalOn[iBeam][iPol]  *= sALFAcalNon[iBeam][iPol];
     2436    sALFAcalOn[iBeam][iPol]  += mean;
     2437    sALFAcalOn[iBeam][iPol]  /= ++sALFAcalNon[iBeam][iPol];
     2438  } else {
     2439    sALFAcalOff[iBeam][iPol] *= sALFAcalNoff[iBeam][iPol];
     2440    sALFAcalOff[iBeam][iPol] += mean;
     2441    sALFAcalOff[iBeam][iPol] /= ++sALFAcalNoff[iBeam][iPol];
     2442  }
     2443
     2444  if (sALFAcalNon[iBeam][iPol] && sALFAcalNoff[iBeam][iPol]) {
     2445    // Tcal should come from the TCAL table, it varies weakly with beam,
     2446    // polarization, and frequency.  However, TCAL is not written properly.
     2447    float Tcal = 12.0f;
     2448    sALFAcal[iBeam][iPol] = Tcal / (sALFAcalOn[iBeam][iPol] -
     2449                                    sALFAcalOff[iBeam][iPol]);
     2450
     2451    // Scale from K to Jy; the gain also varies weakly with beam,
     2452    // polarization, frequency, and zenith angle.
     2453    float fluxCal = 10.0f;
     2454    sALFAcal[iBeam][iPol] /= fluxCal;
     2455  }
     2456
     2457  return 0;
     2458}
     2459
     2460//----------------------------------------------------- SDFITSreader::alfaGain
     2461
     2462// ALFA gain factor.
     2463
     2464float SDFITSreader::alfaGain(
     2465        float zd)
     2466{
     2467  // Gain vs zenith distance table from Robert Minchin, 2008/12/08.
     2468  const int nZD = 37;
     2469  const float zdLim[] = {1.5f, 19.5f};
     2470  const float zdInc = (nZD - 1) / (zdLim[1] - zdLim[0]);
     2471  float zdGain[] = {                                       1.00723708,
     2472                    1.16644573,  1.15003645,  1.07117307,  1.02532673,
     2473                    1.01788402,  1.01369524,  1.00000000,  0.989855111,
     2474                    0.990888834, 0.993996620, 0.989964068, 0.982213855,
     2475                    0.978662670, 0.979349494, 0.978478372, 0.974631131,
     2476                    0.972126007, 0.972835243, 0.972742677, 0.968671739,
     2477                    0.963891327, 0.963452935, 0.966831207, 0.969585896,
     2478                    0.970700860, 0.972644389, 0.973754644, 0.967344403,
     2479                    0.952168941, 0.937160134, 0.927843094, 0.914048433,
     2480                    0.886700928, 0.864701211, 0.869126320, 0.854309499};
     2481
     2482  float gain;
     2483  // Do table lookup by linear interpolation.
     2484  float lambda = zdInc * (zd - zdLim[0]);
     2485  int j = int(lambda);
     2486  if (j < 0) {
     2487    gain = zdGain[0];
     2488  } else if (j >= nZD-1) {
     2489    gain = zdGain[nZD-1];
     2490  } else {
     2491    gain = zdGain[j] + (lambda - j) * (zdGain[j+1] - zdGain[j]);
     2492  }
     2493
     2494  return gain;
     2495}
     2496
Note: See TracChangeset for help on using the changeset viewer.