Changeset 1757 for branches/alma/external/atnf/PKSIO/SDFITSreader.cc
- Timestamp:
- 06/09/10 19:03:06 (14 years ago)
- Location:
- branches/alma
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/alma
-
Property
svn:ignore
set to
.sconf_temp
.sconsign.dblite
-
Property
svn:mergeinfo
set to
/branches/asap-3.x merged eligible
-
Property
svn:ignore
set to
-
branches/alma/external/atnf/PKSIO/SDFITSreader.cc
r1453 r1757 1 1 //#--------------------------------------------------------------------------- 2 //# SDFITSreader.cc: ATNF CFITSIO interface class for SDFITS input.2 //# SDFITSreader.cc: ATNF interface class for SDFITS input using CFITSIO. 3 3 //#--------------------------------------------------------------------------- 4 //# Copyright (C) 2000-20065 //# 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 6 6 //# 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. 11 8 //# 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 13 15 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public15 //# License formore details.16 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 //# more details. 16 18 //# 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/>. 20 21 //# 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 27 29 //# 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 $ 29 32 //#--------------------------------------------------------------------------- 30 33 //# The SDFITSreader class reads single dish FITS files such as those written … … 34 37 //#--------------------------------------------------------------------------- 35 38 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 36 48 #include <algorithm> 37 49 #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> 49 51 50 52 class FITSparm … … 57 59 long nelem; // Column data repeat count; < 0 for vardim. 58 60 int tdimcol; // TDIM column number; 0 for keyword; -1 absent. 61 char units[32]; // Units from TUNITn keyword. 59 62 }; 60 63 … … 64 67 // Factor to convert radians to degrees. 65 68 const double D2R = PI / 180.0; 69 70 // Class name 71 const string className = "SDFITSreader" ; 72 73 //---------------------------------------------------- SDFITSreader::(statics) 74 75 int SDFITSreader::sInit = 1; 76 int SDFITSreader::sReset = 0; 77 int (*SDFITSreader::sALFAcalNon)[2] = (int (*)[2])(new float[16]); 78 int (*SDFITSreader::sALFAcalNoff)[2] = (int (*)[2])(new float[16]); 79 float (*SDFITSreader::sALFAcalOn)[2] = (float (*)[2])(new float[16]); 80 float (*SDFITSreader::sALFAcalOff)[2] = (float (*)[2])(new float[16]); 81 float (*SDFITSreader::sALFAcal)[2] = (float (*)[2])(new float[16]); 66 82 67 83 //------------------------------------------------- SDFITSreader::SDFITSreader … … 70 86 { 71 87 // Default constructor. 72 cSDptr = 0 ;88 cSDptr = 0x0; 73 89 74 90 // Allocate space for data descriptors. … … 85 101 cEndChan = 0x0; 86 102 cRefChan = 0x0; 103 cPols = 0x0; 87 104 } 88 105 … … 113 130 int &extraSysCal) 114 131 { 132 const string methodName = "open()" ; 133 115 134 if (cSDptr) { 116 135 close(); … … 120 139 cStatus = 0; 121 140 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); 124 143 return 1; 125 144 } … … 138 157 cALFA_CIMA = 1; 139 158 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 140 164 } 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."); 143 166 close(); 144 167 return 1; … … 148 171 // Arecibo ALFA data of some kind. 149 172 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; 158 185 } 159 186 } … … 165 192 strncmp(telescope, "NRAO_GBT", 8) == 0; 166 193 167 cRow = 0;168 169 194 170 195 // Check that the DATA array column is present. … … 172 197 haveSpectra = cHaveSpectra = cData[DATA].colnum > 0; 173 198 199 cNAxisTime = 0; 174 200 if (cHaveSpectra) { 175 201 // Find the number of data axes (must be the same for each IF). 176 cNAx is = 5;177 if (readDim(DATA, 1, &cNAx is, cNAxes)) {178 reportError();202 cNAxes = 5; 203 if (readDim(DATA, 1, &cNAxes, cNAxis)) { 204 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 179 205 close(); 180 206 return 1; … … 182 208 183 209 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 185 211 // no TDIM (or MAXISn) card; use the LAGS_IN value. 186 cNAx is = 5;187 readParm("LAGS_IN", TLONG, cNAx es);188 cNAx es[1] = 1;189 cNAx es[2] = 1;190 cNAx es[3] = 1;191 cNAx es[4] = 1;192 cData[DATA].nelem = cNAx es[0];193 } 194 195 if (cNAx is < 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) { 196 222 // 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."); 198 224 close(); 199 225 return 1; 200 } else if (cNAx is > 5) {226 } else if (cNAxes > 5) { 201 227 // 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."); 203 229 close(); 204 230 return 1; … … 211 237 findData(DATAXED, "DATAXED", TSTRING); 212 238 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."); 214 240 close(); 215 241 return 1; … … 220 246 readParm("DATAXED", TSTRING, dataxed); 221 247 222 for (int iaxis = 0; iaxis < 5; iaxis++) cNAx es[iaxis] = 0;223 sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAx es, cNAxes+1, cNAxes+2,224 cNAx es+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); 225 251 for (int iaxis = 4; iaxis > -1; iaxis--) { 226 if (cNAx es[iaxis] == 0) cNAxis = iaxis;252 if (cNAxis[iaxis] == 0) cNAxes = iaxis; 227 253 } 228 254 } … … 235 261 // Find required DATA array axes. 236 262 char ctype[5][72]; 237 for (int iaxis = 0; iaxis < cNAx is; iaxis++) {263 for (int iaxis = 0; iaxis < cNAxes; iaxis++) { 238 264 strcpy(ctype[iaxis], ""); 239 265 readParm(CTYPE[iaxis], TSTRING, ctype[iaxis]); // Core. … … 241 267 242 268 if (cStatus) { 243 reportError();269 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 244 270 close(); 245 271 return 1; 246 272 } 247 273 248 char *fqCRPIX = 0;249 274 char *fqCRVAL = 0; 250 275 char *fqCDELT = 0; 276 char *fqCRPIX = 0; 251 277 char *raCRVAL = 0; 252 278 char *decCRVAL = 0; 253 279 char *timeCRVAL = 0; 280 char *timeCDELT = 0; 281 char *timeCRPIX = 0; 254 282 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++) { 257 293 if (strncmp(ctype[iaxis], "FREQ", 4) == 0) { 258 c Reqax[0]= iaxis;259 fqCR PIX = CRPIX[iaxis];260 fqC RVAL = CRVAL[iaxis];261 fqC DELT = CDELT[iaxis];294 cFreqAxis = iaxis; 295 fqCRVAL = CRVAL[iaxis]; 296 fqCDELT = CDELT[iaxis]; 297 fqCRPIX = CRPIX[iaxis]; 262 298 263 299 } else if (strncmp(ctype[iaxis], "STOKES", 6) == 0) { 264 cReqax[1] = iaxis; 300 cStokesAxis = iaxis; 301 polCRVAL = CRVAL[iaxis]; 265 302 266 303 } else if (strncmp(ctype[iaxis], "RA", 2) == 0) { 267 cR eqax[2]= iaxis;268 raCRVAL = CRVAL[iaxis];304 cRaAxis = iaxis; 305 raCRVAL = CRVAL[iaxis]; 269 306 270 307 } else if (strncmp(ctype[iaxis], "DEC", 3) == 0) { 271 c Reqax[3]= iaxis;272 decCRVAL = CRVAL[iaxis];308 cDecAxis = iaxis; 309 decCRVAL = CRVAL[iaxis]; 273 310 274 311 } 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; 276 315 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 } 277 326 278 327 } else if (strcmp(ctype[iaxis], "BEAM") == 0) { 279 328 // BEAM can be a keyword or axis type. 329 cBeamAxis = iaxis; 280 330 beamCRVAL = CRVAL[iaxis]; 281 331 } … … 284 334 if (cALFA_BD) { 285 335 // Fixed in ALFA CIMAFITS. 286 cR eqax[2]= 2;336 cRaAxis = 2; 287 337 raCRVAL = "CRVAL2A"; 288 338 289 c Reqax[3]= 3;339 cDecAxis = 3; 290 340 decCRVAL = "CRVAL3A"; 291 341 } 292 342 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; 300 349 } 301 350 … … 304 353 findData(CYCLE, "CYCLE", TINT); // Additional. 305 354 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 307 372 findData(EXPOSURE, "EXPOSURE", TFLOAT); // Core. 308 373 findData(OBJECT, "OBJECT", TSTRING); // Core. … … 314 379 findData(BEAM, "BEAM", TSHORT); // Additional. 315 380 findData(IF, "IF", TSHORT); // Additional. 316 findData(FqRefPix, fqCRPIX, TFLOAT); // Frequency reference pixel.317 381 findData(FqRefVal, fqCRVAL, TDOUBLE); // Frequency reference value. 318 382 findData(FqDelt, fqCDELT, TDOUBLE); // Frequency increment. 383 findData(FqRefPix, fqCRPIX, TFLOAT); // Frequency reference pixel. 319 384 findData(RA, raCRVAL, TDOUBLE); // Right ascension. 320 385 findData(DEC, decCRVAL, TDOUBLE); // Declination. … … 343 408 findData(WINDDIRE, "WINDDIRE", TFLOAT); // Shared. 344 409 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 345 418 if (cStatus) { 346 reportError();419 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 347 420 close(); 348 421 return 1; … … 355 428 cALFAscan = 0; 356 429 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) { 358 439 findData(SCAN, "SCAN_NUMBER", TINT); 359 440 findData(CYCLE, "PATTERN_NUMBER", TINT); 360 } else if (cALFA_CIMA) {361 findData(SCAN, "SCAN_ID", TINT);362 findData(CYCLE, "SUBSCAN", TINT);363 441 } 364 442 } else { … … 368 446 cCycleNo = 0; 369 447 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 } 370 453 371 454 // Beam number, 1-relative by default. 372 455 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) { 374 462 if (beamCRVAL) { 375 463 // There is a BEAM axis. 376 464 findData(BEAM, beamCRVAL, TDOUBLE); 377 378 465 } 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); 387 468 cBeam_1rel = 0; 388 469 } … … 393 474 if (cALFA && cData[IF].colnum < 0) { 394 475 // 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 } 396 481 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 }404 482 } 405 483 … … 476 554 fits_get_num_rows(cSDptr, &cNRow, &cStatus); 477 555 if (!cNRow) { 478 cerr << "Table contains no entries." << endl;556 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "Table contains no entries."); 479 557 close(); 480 558 return 1; … … 489 567 if (fits_read_col(cSDptr, TSHORT, cData[BEAM].colnum, 1, 1, cNRow, 490 568 &beamNul, beamCol, &anynul, &cStatus)) { 491 reportError();492 569 delete [] beamCol; 570 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 493 571 close(); 494 572 return 1; … … 504 582 // Check validity. 505 583 if (beamCol[irow] < cBeam_1rel) { 506 cerr << "SDFITS file contains invalid beam number." << endl;507 584 delete [] beamCol; 585 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "SDFITS file contains invalid beam number."); 508 586 close(); 509 587 return 1; … … 545 623 if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow, 546 624 &IFNul, IFCol, &anynul, &cStatus)) { 547 reportError();548 625 delete [] IFCol; 626 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 549 627 close(); 550 628 return 1; … … 560 638 // Check validity. 561 639 if (IFCol[irow] < cIF_1rel) { 562 cerr << "SDFITS file contains invalid IF number." << endl;563 640 delete [] IFCol; 641 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE, "SDFITS file contains invalid IF number."); 564 642 close(); 565 643 return 1; … … 592 670 if (cData[DATA].nelem < 0) { 593 671 // Variable dimension array. 594 if (readDim(DATA, irow+1, &cNAx is, cNAxes)) {595 reportError();672 if (readDim(DATA, irow+1, &cNAxes, cNAxis)) { 673 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 596 674 close(); 597 675 return 1; … … 604 682 readParm("DATAXED", TSTRING, dataxed); 605 683 606 sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAx es, cNAxes+1,607 cNAx es+2, cNAxes+3, cNAxes+4);684 sscanf(dataxed, "(%ld,%ld,%ld,%ld,%ld)", cNAxis, cNAxis+1, 685 cNAxis+2, cNAxis+3, cNAxis+4); 608 686 } 609 687 } 610 688 611 689 // Number of channels and polarizations. 612 cNChan[iIF] = cNAx es[cReqax[0]];613 cNPol[iIF] = cNAx es[cReqax[1]];690 cNChan[iIF] = cNAxis[cFreqAxis]; 691 cNPol[iIF] = cNAxis[cStokesAxis]; 614 692 cHaveXPol[iIF] = 0; 615 693 … … 621 699 622 700 if (readDim(XPOLDATA, irow+1, &nAxis, nAxes)) { 623 reportError();701 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE ); 624 702 close(); 625 703 return 1; … … 650 728 651 729 // Number of channels and polarizations. 652 cNChan[0] = cNAx es[cReqax[0]];653 cNPol[0] = cNAx es[cReqax[1]];730 cNChan[0] = cNAxis[cFreqAxis]; 731 cNPol[0] = cNAxis[cStokesAxis]; 654 732 cHaveXPol[0] = 0; 655 733 } 656 734 657 if (cALFA ) {658 // ALFAlabels each polarization as a separate IF.735 if (cALFA && cALFA_CIMA < 2) { 736 // Older ALFA data labels each polarization as a separate IF. 659 737 cNPol[0] = cNIF; 660 738 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 ; 661 779 } 662 780 … … 712 830 extraSysCal = cExtraSysCal; 713 831 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 714 844 return 0; 715 845 } … … 725 855 double antPos[3], 726 856 char obsMode[32], 857 char bunit[32], 727 858 float &equinox, 728 859 char radecsys[32], … … 733 864 double &bandwidth) 734 865 { 866 const string methodName = "getHeader()" ; 867 735 868 // Has the file been opened? 736 869 if (!cSDptr) { … … 773 906 readData(OBSMODE, 1, obsMode); // Shared. 774 907 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 775 921 readParm("EQUINOX", TFLOAT, &equinox); // Shared. 776 922 if (cStatus == 405) { … … 793 939 794 940 // 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 795 944 if (readParm("VELFRAME", TSTRING, dopplerFrame)) { // Additional. 796 945 // No, try digging it out of the CTYPE card (AIPS convention). 797 946 char keyw[9], ctype[9]; 798 sprintf(keyw, "CTYPE%ld", c Reqax[0]+1);947 sprintf(keyw, "CTYPE%ld", cFreqAxis+1); 799 948 readParm(keyw, TSTRING, ctype); 800 949 … … 804 953 // LSR unqualified usually means LSR (kinematic). 805 954 strcpy(dopplerFrame, "LSRK"); 955 } else if (strcmp(dopplerFrame, "LSD") == 0) { 956 // LSR as a dynamical defintion 957 strcpy(dopplerFrame, "LSRD"); 806 958 } else if (strcmp(dopplerFrame, "HEL") == 0) { 807 959 // Almost certainly barycentric. 808 960 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"); 809 979 } 810 980 } else { … … 812 982 } 813 983 } 814 815 984 // Translate to FITS standard names. 816 985 if (strncmp(dopplerFrame, "TOP", 3) == 0) { … … 822 991 } else if (strncmp(dopplerFrame, "BARY", 4) == 0) { 823 992 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 827 1002 if (cStatus) { 828 reportError();1003 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 829 1004 return 1; 830 1005 } 831 1006 832 1007 // Get parameters from first row of table. 833 readData(DATE_OBS, 1, datobs); 834 readData(TIME, 1, &utc); 1008 readTime(1, 1, datobs, utc); 835 1009 readData(FqRefVal, 1, &refFreq); 836 1010 readParm("BANDWID", TDOUBLE, &bandwidth); // Core. 837 1011 838 if (cALFA_BD) utc *= 3600.0;839 840 1012 if (cStatus) { 841 reportError();1013 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 842 1014 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';867 1015 } 868 1016 … … 879 1027 double* &endFreq) 880 1028 { 1029 const string methodName = "getFreqInfo()" ; 1030 881 1031 float fqRefPix; 882 1032 double fqDelt, fqRefVal; … … 892 1042 if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow, 893 1043 &IFNul, IFCol, &anynul, &cStatus)) { 894 reportError();895 1044 delete [] IFCol; 1045 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 896 1046 close(); 897 1047 return 1; … … 956 1106 double* &positions) 957 1107 { 958 int anynul;1108 const string methodName = "findRange()" ; 959 1109 960 1110 // Has the file been opened? … … 966 1116 967 1117 // 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++) { 970 1120 sel[irow] = 1; 971 1121 } 972 1122 1123 int anynul; 973 1124 if (cData[BEAM].colnum > 0) { 974 1125 short *beamCol = new short[cNRow]; … … 976 1127 if (fits_read_col(cSDptr, TSHORT, cData[BEAM].colnum, 1, 1, cNRow, 977 1128 &beamNul, beamCol, &anynul, &cStatus)) { 978 reportError();979 1129 delete [] beamCol; 980 1130 delete [] sel; 1131 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 981 1132 return 1; 982 1133 } 983 1134 984 for (int irow = 0; irow < nRow; irow++) {1135 for (int irow = 0; irow < cNRow; irow++) { 985 1136 if (!cBeams[beamCol[irow]-cBeam_1rel]) { 986 1137 sel[irow] = 0; … … 996 1147 if (fits_read_col(cSDptr, TSHORT, cData[IF].colnum, 1, 1, cNRow, 997 1148 &IFNul, IFCol, &anynul, &cStatus)) { 998 reportError();999 1149 delete [] IFCol; 1000 1150 delete [] sel; 1151 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1001 1152 return 1; 1002 1153 } 1003 1154 1004 for (int irow = 0; irow < nRow; irow++) {1155 for (int irow = 0; irow < cNRow; irow++) { 1005 1156 if (!cIFs[IFCol[irow]-cIF_1rel]) { 1006 1157 sel[irow] = 0; … … 1012 1163 1013 1164 nSel = 0; 1014 for (int irow = 0; irow < nRow; irow++) {1165 for (int irow = 0; irow < cNRow; irow++) { 1015 1166 nSel += sel[irow]; 1016 1167 } … … 1018 1169 1019 1170 // 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]); 1055 1173 1056 1174 1057 1175 // 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 1072 1176 int isel = 0; 1073 1177 positions = new double[2*nSel]; 1074 1178 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 } 1112 1251 1113 1252 } 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 1331 cleanup: 1122 1332 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; 1127 1343 } 1128 1344 … … 1133 1349 1134 1350 int SDFITSreader::read( 1135 PKSMBrecord &mbrec)1351 MBrecord &mbrec) 1136 1352 { 1353 const string methodName = "read()" ; 1354 1137 1355 // Has the file been opened? 1138 1356 if (!cSDptr) { 1139 1357 return 1; 1140 1358 } 1141 1142 1359 // Find the next selected beam and IF. 1143 1360 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 1145 1368 if (cData[BEAM].colnum > 0) { 1146 1369 readData(BEAM, cRow, &iBeam); … … 1164 1387 char chars[32]; 1165 1388 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. 1169 1391 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 } 1170 1422 } 1171 1423 } 1172 1424 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 } 1173 1435 break; 1174 1436 } … … 1200 1462 // Times. 1201 1463 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); 1228 1465 strcpy(mbrec.datobs, datobs); 1229 1466 1230 1467 if (cData[CYCLE].colnum > 0) { 1231 1468 readData(CYCLE, cRow, &mbrec.cycleNo); 1469 mbrec.cycleNo += cTimeIdx - 1; 1232 1470 if (cALFA_BD) mbrec.cycleNo++; 1233 1471 } else { … … 1239 1477 } 1240 1478 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 1241 1490 readData(EXPOSURE, cRow, &mbrec.exposure); 1242 1491 1243 1492 // 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 } 1245 1539 1246 1540 readData(OBJ_RA, cRow, &mbrec.srcRA); … … 1279 1573 mbrec.decRate = scanrate[1] * D2R; 1280 1574 } 1575 mbrec.paRate = 0.0f; 1281 1576 1282 1577 // IF-dependent parameters. … … 1289 1584 int nPol = cNPol[iIF]; 1290 1585 1586 if ( cData[STOKES].colnum > 0 ) 1587 nPol = 1 ; 1588 1291 1589 if (cGetSpectra || cGetXPol) { 1292 1590 int nxpol = cGetXPol ? 2*nChan : 0; … … 1298 1596 mbrec.nChan[0] = nChan; 1299 1597 mbrec.nPol[0] = nPol; 1598 mbrec.polNo = iPol ; 1300 1599 1301 1600 readData(FqRefPix, cRow, mbrec.fqRefPix); … … 1316 1615 1317 1616 if (cStatus) { 1318 reportError();1617 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1319 1618 return 1; 1320 1619 } … … 1353 1652 1354 1653 if (cStatus) { 1355 reportError();1654 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1356 1655 return 1; 1357 1656 } 1358 1657 1359 1658 // Read data, sectioning and transposing it in the process. 1360 long *blc = new long[cNAx is+1];1361 long *trc = new long[cNAx is+1];1362 long *inc = new long[cNAx is+1];1363 for (int iaxis = 0; iaxis <= cNAx is; 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++) { 1364 1663 blc[iaxis] = 1; 1365 1664 trc[iaxis] = 1; … … 1367 1666 } 1368 1667 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; 1373 1676 1374 1677 mbrec.haveSpectra = cGetSpectra; … … 1376 1679 int anynul; 1377 1680 1378 for (int i pol = 0; ipol < nPol; ipol++) {1379 blc[c Reqax[1]] = ipol+1;1380 trc[c Reqax[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) { 1383 1686 // ALFA data: polarizations are stored in successive rows. 1384 blc[c Reqax[1]] = 1;1385 trc[c Reqax[1]] = 1;1386 1387 if (i pol) {1687 blc[cStokesAxis] = 1; 1688 trc[cStokesAxis] = 1; 1689 1690 if (iPol) { 1388 1691 if (++cRow > cNRow) { 1389 1692 return -1; 1390 1693 } 1391 1694 1392 blc[cNAx is] = cRow;1393 trc[cNAx is] = cRow;1695 blc[cNAxes] = cRow; 1696 trc[cNAxes] = cRow; 1394 1697 } 1395 1698 1396 1699 } else if (cData[DATA].nelem < 0) { 1397 1700 // Variable dimension array; get axis lengths. 1398 int naxis = 5, status;1399 1400 if ((status = readDim(DATA, cRow, &nax is, cNAxes))) {1401 reportError();1402 1403 } else if ((status = (nax is != 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."); 1405 1708 } 1406 1709 … … 1413 1716 } 1414 1717 1415 if (fits_read_subset_flt(cSDptr, cData[DATA].colnum, cNAx is, cNAxes,1416 blc, trc, inc, 0, mbrec.spectra[0] + i pol*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, 1417 1720 &cStatus)) { 1418 reportError();1721 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1419 1722 delete [] blc; 1420 1723 delete [] trc; … … 1425 1728 if (endChan < startChan) { 1426 1729 // Reverse the spectrum. 1427 float *iptr = mbrec.spectra[0] + i pol*nChan;1730 float *iptr = mbrec.spectra[0] + iPol*nChan; 1428 1731 float *jptr = iptr + nChan - 1; 1429 1732 float *mid = iptr + nChan/2; … … 1437 1740 if (cALFA) { 1438 1741 // 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; 1440 1758 float *chanN = chan + nChan; 1441 1759 while (chan < chanN) { 1442 1760 // Approximate conversion to Jy. 1443 *(chan++) *= cALFAcal[iBeam][iIF];1761 *(chan++) *= factor; 1444 1762 } 1445 1763 } 1446 1764 1447 if (mbrec.tsys[0][i pol] == 0.0) {1765 if (mbrec.tsys[0][iPol] == 0.0) { 1448 1766 // Compute Tsys as the average across the spectrum. 1449 float *chan = mbrec.spectra[0] + i pol*nChan;1767 float *chan = mbrec.spectra[0] + iPol*nChan; 1450 1768 float *chanN = chan + nChan; 1451 float *tsys = mbrec.tsys[0] + i pol;1769 float *tsys = mbrec.tsys[0] + iPol; 1452 1770 while (chan < chanN) { 1453 1771 *tsys += *(chan++); … … 1459 1777 // Read data flags. 1460 1778 if (cData[FLAGGED].colnum > 0) { 1461 if (fits_read_subset_byt(cSDptr, cData[FLAGGED].colnum, cNAx is,1462 cNAx es, 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, 1463 1781 &cStatus)) { 1464 reportError();1782 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1465 1783 delete [] blc; 1466 1784 delete [] trc; … … 1471 1789 if (endChan < startChan) { 1472 1790 // Reverse the flag vector. 1473 unsigned char *iptr = mbrec.flagged[0] + i pol*nChan;1791 unsigned char *iptr = mbrec.flagged[0] + iPol*nChan; 1474 1792 unsigned char *jptr = iptr + nChan - 1; 1475 1793 for (int ichan = 0; ichan < nChan/2; ichan++) { … … 1482 1800 } else { 1483 1801 // All channels are unflagged by default. 1484 unsigned char *iptr = mbrec.flagged[0] + i pol*nChan;1802 unsigned char *iptr = mbrec.flagged[0] + iPol*nChan; 1485 1803 for (int ichan = 0; ichan < nChan; ichan++) { 1486 1804 *(iptr++) = 0; … … 1513 1831 if (fits_read_subset_flt(cSDptr, cData[XPOLDATA].colnum, nAxis, nAxes, 1514 1832 blc, trc, inc, 0, mbrec.xpol[0], &anynul, &cStatus)) { 1515 reportError();1833 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1516 1834 delete [] blc; 1517 1835 delete [] trc; … … 1544 1862 1545 1863 if (cStatus) { 1546 reportError();1864 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1547 1865 return 1; 1548 1866 } … … 1552 1870 readData(TCAL, cRow, &mbrec.tcal[0]); 1553 1871 readData(TCALTIME, cRow, mbrec.tcalTime); 1872 1554 1873 readData(AZIMUTH, cRow, &mbrec.azimuth); 1555 1874 readData(ELEVATIO, cRow, &mbrec.elevation); 1556 1875 readData(PARANGLE, cRow, &mbrec.parAngle); 1876 1557 1877 readData(FOCUSAXI, cRow, &mbrec.focusAxi); 1558 1878 readData(FOCUSTAN, cRow, &mbrec.focusTan); 1559 1879 readData(FOCUSROT, cRow, &mbrec.focusRot); 1880 1560 1881 readData(TAMBIENT, cRow, &mbrec.temp); 1561 1882 readData(PRESSURE, cRow, &mbrec.pressure); … … 1575 1896 mbrec.windAz *= D2R; 1576 1897 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 1577 1908 if (cStatus) { 1578 reportError();1909 log(LogOrigin( className, methodName, WHERE ), LogIO::SEVERE); 1579 1910 return 1; 1580 1911 } 1581 1912 1582 1913 return 0; 1583 }1584 1585 1586 //------------------------------------------------------ SDFITSreader::alfaCal1587 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::reportError1690 1691 // Print the error message corresponding to the input status value and all the1692 // messages on the CFITSIO error stack to stderr.1693 1694 void SDFITSreader::reportError()1695 {1696 fits_report_error(stderr, cStatus);1697 1914 } 1698 1915 … … 1706 1923 int status = 0; 1707 1924 fits_close_file(cSDptr, &status); 1708 cSDptr = 0 ;1925 cSDptr = 0x0; 1709 1926 1710 1927 if (cBeams) delete [] cBeams; … … 1714 1931 if (cRefChan) delete [] cRefChan; 1715 1932 } 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 1940 void 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 ; 1716 1955 } 1717 1956 … … 1737 1976 long nelem, width; 1738 1977 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); 1739 1980 1740 1981 // Look for a TDIMnnn keyword or column. … … 1768 2009 } 1769 2010 2011 //------------------------------------------------------ SDFITSreader::findCol 2012 2013 // Locate a parameter in the SDFITS file. 2014 2015 void 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 1770 2039 //------------------------------------------------------ SDFITSreader::readDim 1771 2040 … … 1775 2044 int iData, 1776 2045 long iRow, 1777 int *nax is,1778 long nax es[])2046 int *naxes, 2047 long naxis[]) 1779 2048 { 1780 2049 int colnum = cData[iData].colnum; … … 1783 2052 } 1784 2053 1785 int maxdim = *nax is;2054 int maxdim = *naxes; 1786 2055 if (cData[iData].tdimcol < 0) { 1787 2056 // No TDIMnnn column for this array. 1788 2057 if (cData[iData].nelem < 0) { 1789 2058 // Variable length array; read the array descriptor. 1790 *nax is = 1;2059 *naxes = 1; 1791 2060 long dummy; 1792 if (fits_read_descript(cSDptr, colnum, iRow, nax es, &dummy, &cStatus)) {2061 if (fits_read_descript(cSDptr, colnum, iRow, naxis, &dummy, &cStatus)) { 1793 2062 return 1; 1794 2063 } … … 1796 2065 } else { 1797 2066 // Read the repeat count from TFORMnnn. 1798 if (fits_read_tdim(cSDptr, colnum, maxdim, nax is, naxes, &cStatus)) {2067 if (fits_read_tdim(cSDptr, colnum, maxdim, naxes, naxis, &cStatus)) { 1799 2068 return 1; 1800 2069 } … … 1814 2083 1815 2084 tp++; 1816 *nax is = 0;2085 *naxes = 0; 1817 2086 for (size_t j = 1; j < strlen(tdimval); j++) { 1818 2087 if (tdimval[j] == ',' || tdimval[j] == ')') { 1819 sscanf(tp, "%ld", nax es + (*naxis)++);2088 sscanf(tp, "%ld", naxis + (*naxes)++); 1820 2089 if (tdimval[j] == ')') break; 1821 2090 tp = tdimval + j + 1; … … 1852 2121 findCol(name, &colnum); 1853 2122 1854 if (colnum > 0 ) {2123 if (colnum > 0 && iRow > 0) { 1855 2124 // Read the first value from the specified row of the table. 1856 2125 int coltype; … … 1915 2184 void *value) 1916 2185 { 1917 char *name = cData[iData].name;1918 2186 int type = cData[iData].type; 1919 2187 int colnum = cData[iData].colnum; 1920 long nelem = cData[iData].nelem; 1921 1922 if (colnum > 0) { 2188 2189 if (colnum > 0 && iRow > 0) { 1923 2190 // Read the required number of values from the specified row of the table. 2191 long nelem = cData[iData].nelem; 1924 2192 int anynul; 1925 2193 if (type == TSTRING) { … … 1950 2218 } else if (colnum == 0) { 1951 2219 // Read keyword value. 2220 char *name = cData[iData].name; 1952 2221 fits_read_key(cSDptr, type, name, value, 0, &cStatus); 1953 2222 … … 1970 2239 } 1971 2240 1972 //------------------------------------------------------ SDFITSreader:: findCol1973 1974 // Locate a parameter inthe 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 2245 int SDFITSreader::readCol( 2246 int iData, 2247 void *value) 1979 2248 { 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; 1998 2274 } 2275 2276 //----------------------------------------------------- SDFITSreader::readTime 2277 2278 // Read the time from the SDFITS file. 2279 2280 int 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 2338 int 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 2464 float 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.