source: branches/alma/external/atnf/PKSIO/MBFITSreader.cc @ 1386

Last change on this file since 1386 was 1372, checked in by mar637, 17 years ago

latest update from livedata CVS. This has the Hobart position fix

File size: 35.8 KB
Line 
1//#---------------------------------------------------------------------------
2//# MBFITSreader.cc: ATNF single-dish RPFITS reader.
3//#---------------------------------------------------------------------------
4//# Copyright (C) 2000-2007
5//# Mark Calabretta, ATNF
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.
11//#
12//# This library is distributed in the hope that it will be useful, but WITHOUT
13//# 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//#
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.
20//#
21//# Correspondence concerning this software should be addressed as follows:
22//#        Internet email: mcalabre@atnf.csiro.au.
23//#        Postal address: Dr. Mark Calabretta,
24//#                        Australia Telescope National Facility,
25//#                        P.O. Box 76,
26//#                        Epping, NSW, 2121,
27//#                        AUSTRALIA
28//#
29//# $Id: MBFITSreader.cc,v 19.34 2007/07/02 06:12:18 cal103 Exp $
30//#---------------------------------------------------------------------------
31//# The MBFITSreader class reads single dish RPFITS files (such as Parkes
32//# Multibeam MBFITS files).
33//#
34//# Original: 2000/07/28 Mark Calabretta
35//#---------------------------------------------------------------------------
36
37#include <atnf/PKSIO/MBFITSreader.h>
38#include <atnf/PKSIO/PKSMBrecord.h>
39
40#include <RPFITS.h>
41
42#include <casa/math.h>
43#include <casa/iostream.h>
44#include <casa/stdio.h>
45#include <casa/stdlib.h>
46#include <casa/string.h>
47#include <unistd.h>
48
49using namespace std;
50
51// Numerical constants.
52const double PI = 3.141592653589793238462643;
53const double TWOPI = 2.0 * PI;
54
55//------------------------------------------------- MBFITSreader::MBFITSreader
56
57// Default constructor.
58
59MBFITSreader::MBFITSreader(
60        const int retry,
61        const int interpolate)
62{
63  cRetry = retry;
64  if (cRetry > 10) {
65    cRetry = 10;
66  }
67
68  cInterp = interpolate;
69  if (cInterp < 0 || cInterp > 2) {
70    cInterp = 1;
71  }
72
73  // Initialize pointers.
74  cBeams     = 0x0;
75  cIFs       = 0x0;
76  cNChan     = 0x0;
77  cNPol      = 0x0;
78  cHaveXPol  = 0x0;
79  cStartChan = 0x0;
80  cEndChan   = 0x0;
81  cRefChan   = 0x0;
82
83  cVis = 0x0;
84  cWgt = 0x0;
85
86  cBeamSel   = 0x0;
87  cIFSel     = 0x0;
88  cChanOff   = 0x0;
89  cXpolOff   = 0x0;
90  cBuffer    = 0x0;
91  cPosUTC    = 0x0;
92
93  cMBopen = 0;
94}
95
96//------------------------------------------------ MBFITSreader::~MBFITSreader
97
98// Destructor.
99
100MBFITSreader::~MBFITSreader()
101{
102  close();
103}
104
105//--------------------------------------------------------- MBFITSreader::open
106
107// Open the RPFITS file for reading.
108
109int MBFITSreader::open(
110        char *rpname,
111        int  &nBeam,
112        int* &beams,
113        int  &nIF,
114        int* &IFs,
115        int* &nChan,
116        int* &nPol,
117        int* &haveXPol,
118        int  &haveBase,
119        int  &haveSpectra,
120        int  &extraSysCal)
121{
122  if (cMBopen) {
123    close();
124  }
125
126  strcpy(names_.file, rpname);
127
128  // Open the RPFITS file.
129  int jstat = -3;
130  rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
131            &cBin, &cIFno, &cSrcNo);
132
133  if (jstat) {
134    fprintf(stderr, "ERROR, failed to open MBFITS file: %s\n", rpname);
135    return 1;
136  }
137
138  cMBopen = 1;
139
140  // Tell RPFITSIN that we want the OBSTYPE card.
141  int j;
142  param_.ncard = 1;
143  for (j = 0; j < 80; j++) {
144    names_.card[j] = ' ';
145  }
146  strncpy(names_.card, "OBSTYPE", 7);
147
148  // Read the first header.
149  jstat = -1;
150  rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
151            &cBin, &cIFno, &cSrcNo);
152
153  if (jstat) {
154    fprintf(stderr, "ERROR, failed to read MBFITS header: %s\n", rpname);
155    close();
156    return 1;
157  }
158
159  // Mopra data has some peculiarities.
160  cMopra = strncmp(names_.instrument, "ATMOPRA", 7) == 0;
161
162  // Non-ATNF data may not store the position in (u,v,w).
163  if (strncmp(names_.sta, "tid", 3) == 0) {
164    fprintf(stderr, "WARNING, found Tidbinbilla data");
165    cSUpos = 1;
166  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
167    fprintf(stderr, "WARNING, found Hobart data");
168    cSUpos = 1;
169  } else if (strncmp(names_.sta, "CED", 3) == 0) {
170    fprintf(stderr, "WARNING, found Ceduna data");
171    cSUpos = 1;
172  } else {
173    cSUpos = 0;
174  }
175
176  if (cSUpos) {
177    fprintf(stderr, ", using telescope position from SU table.\n");
178    cInterp = 0;
179  }
180
181
182  // Find the maximum beam number.
183  cNBeam = 0;
184  for (int iBeam = 0; iBeam < anten_.nant; iBeam++) {
185    if (anten_.ant_num[iBeam] > cNBeam) {
186      cNBeam = anten_.ant_num[iBeam];
187    }
188  }
189
190  if (cNBeam <= 0) {
191    fprintf(stderr, "ERROR, couldn't determine number of beams.\n");
192    close();
193    return 1;
194  }
195
196  // Construct the beam mask.
197  cBeams = new int[cNBeam];
198  for (int iBeam = 0; iBeam < cNBeam; iBeam++) {
199    cBeams[iBeam] = 0;
200  }
201
202  // ...beams present in the data.
203  for (int iBeam = 0; iBeam < anten_.nant; iBeam++) {
204    cBeams[anten_.ant_num[iBeam] - 1] = 1;
205  }
206
207  // Passing back the address of the array allows PKSFITSreader::select() to
208  // modify its elements directly.
209  nBeam = cNBeam;
210  beams = cBeams;
211
212
213  // Number of IFs.
214  cNIF = if_.n_if;
215  cIFs = new int[cNIF];
216  for (int iIF = 0; iIF < cNIF; iIF++) {
217    cIFs[iIF] = 1;
218  }
219
220  // Passing back the address of the array allows PKSFITSreader::select() to
221  // modify its elements directly.
222  nIF = cNIF;
223  IFs = cIFs;
224
225
226  // Number of channels and polarizations.
227  cNChan    = new int[cNIF];
228  cNPol     = new int[cNIF];
229  cHaveXPol = new int[cNIF];
230  cGetXPol  = 0;
231
232  int maxProd = 0;
233  for (int iIF = 0; iIF < cNIF; iIF++) {
234    cNChan[iIF] = if_.if_nfreq[iIF];
235    cNPol[iIF]  = if_.if_nstok[iIF];
236    cNChan[iIF] -= cNChan[iIF]%2;
237
238    // Do we have cross-polarization data?
239    if ((cHaveXPol[iIF] = cNPol[iIF] > 2)) {
240      // Cross-polarization data is handled separately.
241      cNPol[iIF] = 2;
242
243      // Default is to get it if we have it.
244      cGetXPol = 1;
245    }
246
247    // Maximum number of spectral products in any IF.
248    int nProd = if_.if_nfreq[iIF] * if_.if_nstok[iIF];
249    if (maxProd < nProd) maxProd = nProd;
250  }
251
252  // Allocate memory for RPFITSIN subroutine arguments.
253  if (cVis) delete [] cVis;
254  if (cWgt) delete [] cWgt;
255  cVis = new float[2*maxProd];
256  cWgt = new float[maxProd];
257
258  nChan    = cNChan;
259  nPol     = cNPol;
260  haveXPol = cHaveXPol;
261
262
263  // Default channel range selection.
264  cStartChan = new int[cNIF];
265  cEndChan   = new int[cNIF];
266  cRefChan   = new int[cNIF];
267
268  for (int iIF = 0; iIF < cNIF; iIF++) {
269    cStartChan[iIF] = 1;
270    cEndChan[iIF] = cNChan[iIF];
271    cRefChan[iIF] = cNChan[iIF]/2 + 1;
272  }
273
274  cGetSpectra = 1;
275
276
277  // No baseline parameters in MBFITS.
278  haveBase = 0;
279
280  // Always have spectra in MBFITS.
281  haveSpectra = cHaveSpectra = 1;
282
283
284  // Integration cycle time (s).
285  cIntTime = param_.intime;
286
287  // Can't deduce binning mode till later.
288  cNBin = 0;
289
290
291  // Read the first syscal record.
292  if (rpget(1, cEOS)) {
293    fprintf(stderr, "ERROR, failed to read first syscal record.\n");
294    close();
295    return 1;
296  }
297
298  // Additional information for Parkes Multibeam data?
299  extraSysCal = (sc_.sc_ant > anten_.nant);
300
301
302  cFirst = 1;
303  cEOF = 0;
304  cFlushing = 0;
305
306  return 0;
307}
308
309//---------------------------------------------------- MBFITSreader::getHeader
310
311// Get parameters describing the data.
312
313int MBFITSreader::getHeader(
314        char   observer[32],
315        char   project[32],
316        char   telescope[32],
317        double antPos[3],
318        char   obsType[32],
319        float  &equinox,
320        char   radecsys[32],
321        char   dopplerFrame[32],
322        char   datobs[32],
323        double &utc,
324        double &refFreq,
325        double &bandwidth)
326{
327  if (!cMBopen) {
328    fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
329    return 1;
330  }
331
332  sprintf(observer,  "%-16.16s", names_.rp_observer);
333  sprintf(project,   "%-16.16s", names_.object);
334  sprintf(telescope, "%-16.16s", names_.instrument);
335
336  // Observatory coordinates (ITRF), in m.
337  antPos[0] = doubles_.x[0];
338  antPos[1] = doubles_.y[0];
339  antPos[2] = doubles_.z[0];
340
341  // This is the only sure way to identify the telescope, maybe.
342  if (strncmp(names_.sta, "MB0", 3) == 0) {
343    // Parkes Multibeam.
344    sprintf(telescope, "%-16.16s", "ATPKSMB");
345    antPos[0] = -4554232.087;
346    antPos[1] =  2816759.046;
347    antPos[2] = -3454035.950;
348  } else if (strncmp(names_.sta, "HOH", 3) == 0) {
349    // Parkes HOH receiver.
350    sprintf(telescope, "%-16.16s", "ATPKSHOH");
351    antPos[0] = -4554232.087;
352    antPos[1] =  2816759.046;
353    antPos[2] = -3454035.950;
354  } else if (strncmp(names_.sta, "CA0", 3) == 0) {
355    // An ATCA antenna, use the array centre position.
356    sprintf(telescope, "%-16.16s", "ATCA");
357    antPos[0] = -4750915.837;
358    antPos[1] =  2792906.182;
359    antPos[2] = -3200483.747;
360  } else if (strncmp(names_.sta, "MOP", 3) == 0) {
361    // Mopra.
362    sprintf(telescope, "%-16.16s", "ATMOPRA");
363    antPos[0] = -4682768.630;
364    antPos[1] =  2802619.060;
365    antPos[2] = -3291759.900;
366  } else if (strncmp(names_.sta, "HOB", 3) == 0) {
367    // Hobart.
368    sprintf(telescope, "%-16.16s", "HOBART");
369    antPos[0] = -3950236.735;
370    antPos[1] =  2522347.567;
371    antPos[2] = -4311562.569;
372  } else if (strncmp(names_.sta, "CED", 3) == 0) {
373    // Ceduna.
374    sprintf(telescope, "%-16.16s", "CEDUNA");
375    antPos[0] = -3749943.657;
376    antPos[1] =  3909017.709;
377    antPos[2] = -3367518.309;
378  } else if (strncmp(names_.sta, "tid", 3) == 0) {
379    // DSS.
380    sprintf(telescope, "%-16.16s", "DSS-43");
381    antPos[0] = -4460894.727;
382    antPos[1] =  2682361.530;
383    antPos[2] = -3674748.424;
384  }
385
386  // Observation type.
387  int j;
388  for (j = 0; j < 31; j++) {
389    obsType[j] = names_.card[11+j];
390    if (obsType[j] == '\'') break;
391  }
392  obsType[j] = '\0';
393
394  // Coordinate frames.
395  equinox = 2000.0f;
396  strcpy(radecsys, "FK5");
397  strcpy(dopplerFrame, "TOPOCENT");
398
399  // Time at start of observation.
400  sprintf(datobs, "%-10.10s", names_.datobs);
401  utc = cUTC;
402
403  // Spectral parameters.
404  refFreq   = doubles_.if_freq[0];
405  bandwidth = doubles_.if_bw[0];
406
407  return 0;
408}
409
410//-------------------------------------------------- MBFITSreader::getFreqInfo
411
412// Get frequency parameters for each IF.
413
414int MBFITSreader::getFreqInfo(
415        int     &nIF,
416        double* &startFreq,
417        double* &endFreq)
418{
419  // This is RPFITS - can't do it!
420  return 1;
421}
422
423//---------------------------------------------------- MBFITSreader::findRange
424
425// Find the range of the data selected in time and position.
426
427int MBFITSreader::findRange(
428        int    &nRow,
429        int    &nSel,
430        char   dateSpan[2][32],
431        double utcSpan[2],
432        double* &positions)
433{
434  // This is RPFITS - can't do it!
435  return 1;
436}
437
438//--------------------------------------------------------- MBFITSreader::read
439
440// Read the next data record.
441
442int MBFITSreader::read(
443        PKSMBrecord &MBrec)
444{
445  int beamNo = -1;
446  int haveData, status;
447  PKSMBrecord *iMBuff = 0x0;
448
449  if (!cMBopen) {
450    fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
451    return 1;
452  }
453
454  // Positions recorded in the input records do not coincide with the midpoint
455  // of the integration and hence the input must be buffered so that true
456  // positions may be interpolated.
457  //
458  // On the first call nBeamSel buffers of length nBin, are allocated and
459  // filled, where nBin is the number of time bins.
460  //
461  // The input records for binned, single beam data with multiple simultaneous
462  // IFs are ordered by IF within each integration rather than by bin number
463  // and hence are not in time order.  No multibeam data exists with
464  // nBin > 1 but the likelihood that the input records would be in beam/IF
465  // order and the requirement that output records be in time order would
466  // force an elaborate double-buffering system and we do not support it.
467  //
468  // Once all buffers are filled, the next record for each beam pertains to
469  // the next integration and should contain new position information allowing
470  // the proper position for each spectrum in the buffer to be interpolated.
471  // The buffers are then flushed in time order.  For single beam data there
472  // is only one buffer and reads from the MBFITS file are suspended while the
473  // flush is in progress.  For multibeam data each buffer is of unit length
474  // so the flush completes immediately and the new record takes its place.
475
476  haveData = 0;
477  while (!haveData) {
478    int iBeamSel = -1, iIFSel = -1;
479
480    if (!cFlushing) {
481      if (cEOF) {
482        return -1;
483      }
484
485      // Read the next record.
486      if ((status = rpget(0, cEOS)) == -1) {
487        // EOF.
488        cEOF = 1;
489        cFlushing = 1;
490        cFlushBin = 0;
491        cFlushIF  = 0;
492
493#ifdef PKSIO_DEBUG
494        printf("End-of-file detected, flushing last scan.\n");
495#endif
496
497      } else if (status) {
498        // IO error.
499        return 1;
500
501      } else {
502        if (cFirst) {
503          // First data; cBeamSel[] stores the buffer index for each beam.
504          cNBeamSel = 0;
505          cBeamSel = new int[cNBeam];
506
507          for (int iBeam = 0; iBeam < cNBeam; iBeam++) {
508            if (cBeams[iBeam]) {
509              // Buffer offset for this beam.
510              cBeamSel[iBeam] = cNBeamSel++;
511            } else {
512              // Signal that the beam is not selected.
513              cBeamSel[iBeam] = -1;
514            }
515          }
516
517          // Set up bookkeeping arrays for IFs.
518          cIFSel   = new int[cNIF];
519          cChanOff = new int[cNIF];
520          cXpolOff = new int[cNIF];
521
522          int simulIF = 0;
523          int maxChan = 0;
524          int maxXpol = 0;
525
526          for (int iIF = 0; iIF < cNIF; iIF++) {
527            if (cIFs[iIF]) {
528              // Buffer index for each IF within each simultaneous set.
529              cIFSel[iIF] = 0;
530
531              // Array offsets for each IF within each simultaneous set.
532              cChanOff[iIF] = 0;
533              cXpolOff[iIF] = 0;
534
535              // Look for earlier IFs in the same simultaneous set.
536              for (int jIF = 0; jIF < iIF; jIF++) {
537                if (!cIFs[jIF]) continue;
538
539                if (if_.if_simul[jIF] == if_.if_simul[iIF]) {
540                  // Got one, increment indices.
541                  cIFSel[iIF]++;
542
543                  cChanOff[iIF] += cNChan[jIF] * cNPol[jIF];
544                  if (cHaveXPol[jIF]) {
545                    cXpolOff[iIF] += 2 * cNChan[jIF];
546                  }
547                }
548              }
549
550              // Maximum number of selected IFs in any simultaneous set.
551              simulIF = max(simulIF, cIFSel[iIF]+1);
552
553              // Maximum memory required for any simultaneous set.
554              maxChan = max(maxChan, cChanOff[iIF] + cNChan[iIF]*cNPol[iIF]);
555              if (cHaveXPol[iIF]) {
556                maxXpol = max(maxXpol, cXpolOff[iIF] + 2*cNChan[iIF]);
557              }
558
559            } else {
560              // Signal that the IF is not selected.
561              cIFSel[iIF] = -1;
562            }
563          }
564
565          // Check for binning mode observations.
566          if (param_.intbase > 0.0f) {
567            cNBin = int((cIntTime / param_.intbase) + 0.5);
568
569            // intbase sometimes contains rubbish.
570            if (cNBin == 0) {
571              cNBin = 1;
572            }
573          } else {
574            cNBin = 1;
575          }
576
577          if (cNBin > 1 && cNBeamSel > 1) {
578            fprintf(stderr, "ERROR, cannot handle binning mode for multiple "
579                            "beams.\n");
580            close();
581            return 1;
582          }
583
584          // Allocate buffer data storage; the PKSMBrecord constructor zeroes
585          // class members such as cycleNo that are tested in the first pass
586          // below.
587          int nBuff = cNBeamSel * cNBin;
588          cBuffer = new PKSMBrecord[nBuff];
589
590          // Allocate memory for spectral arrays.
591          for (int ibuff = 0; ibuff < nBuff; ibuff++) {
592            cBuffer[ibuff].setNIFs(simulIF);
593            cBuffer[ibuff].allocate(0, maxChan, maxXpol);
594          }
595
596          cPosUTC = new double[cNBeamSel];
597
598          cFirst = 0;
599          cScanNo  = 1;
600          cCycleNo = 0;
601          cPrevUTC = 0.0;
602          cStaleness = new int[cNBeamSel];
603          for (int iBeamSel = 0; iBeamSel < cNBeamSel; iBeamSel++) {
604            cStaleness[iBeamSel] = 0;
605          }
606        }
607
608        // Check for end-of-scan.
609        if (cEOS) {
610          cScanNo++;
611          cCycleNo = 0;
612          cPrevUTC = 0.0;
613        }
614
615        // Apply beam selection.
616        beamNo = int(cBaseline / 256.0);
617        iBeamSel = cBeamSel[beamNo-1];
618        if (iBeamSel < 0) continue;
619
620        // Sanity check (mainly for MOPS).
621        if (cIFno > cNIF) continue;
622
623        // Apply IF selection.
624        iIFSel = cIFSel[cIFno - 1];
625        if (iIFSel < 0) continue;
626
627        sprintf(cDateObs, "%-10.10s", names_.datobs);
628
629        // Check for change-of-day.
630        if (cUTC < cPrevUTC - 85800.0) {
631          cUTC += 86400.0;
632        }
633
634        if (cNBin > 1) {
635          // Binning mode: correct the time.
636          cUTC += param_.intbase * (cBin - (cNBin + 1)/2.0);
637        }
638
639        // New integration cycle?
640        if (cUTC > cPrevUTC) {
641          cCycleNo++;
642          cPrevUTC = cUTC + 0.0001;
643        }
644
645        // Compute buffer number.
646        iMBuff = cBuffer + iBeamSel;
647        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
648
649        if (cCycleNo < iMBuff->cycleNo) {
650          // Note that if the first beam and IF are not both selected cEOS
651          // will be cleared by rpget() when the next beam/IF is read.
652          cEOS = 1;
653        }
654
655        // Begin flush cycle?
656        if (cEOS || (iMBuff->nIF && cUTC > iMBuff->utc + 0.0001)) {
657          cFlushing = 1;
658          cFlushBin = 0;
659          cFlushIF  = 0;
660        }
661
662#ifdef PKSIO_DEBUG
663        printf(" In:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, cIFno);
664        if (cEOS) printf("Start of new scan, flushing previous scan.\n");
665#endif
666      }
667    }
668
669
670    if (cFlushing) {
671      // Find the oldest integration to flush, noting that the last
672      // integration cycle may be incomplete.
673      beamNo = 0;
674      int cycleNo = 0;
675      for (; cFlushBin < cNBin; cFlushBin++) {
676        for (iBeamSel = 0; iBeamSel < cNBeamSel; iBeamSel++) {
677          iMBuff = cBuffer + iBeamSel + cNBeamSel*cFlushBin;
678
679          // iMBuff->nIF is set to zero (below) to signal that all IFs in
680          // an integration have been flushed.
681          if (iMBuff->nIF) {
682            if (cycleNo == 0 || iMBuff->cycleNo < cycleNo) {
683              beamNo  = iMBuff->beamNo;
684              cycleNo = iMBuff->cycleNo;
685            }
686          }
687        }
688
689        if (beamNo) {
690          // Found an integration to flush.
691          break;
692        }
693      }
694
695      if (beamNo) {
696        iBeamSel = cBeamSel[beamNo-1];
697        iMBuff = cBuffer + iBeamSel + cNBeamSel*cFlushBin;
698
699        // Find the IF to flush.
700        for (; cFlushIF < iMBuff->nIF; cFlushIF++) {
701          if (iMBuff->IFno[cFlushIF]) break;
702        }
703
704      } else {
705        // Flush complete.
706        cFlushing = 0;
707        if (cEOF) {
708          return -1;
709        }
710
711        // The last record read must have been the first of a new cycle.
712        beamNo = int(cBaseline / 256.0);
713        iBeamSel = cBeamSel[beamNo-1];
714
715        // Compute buffer number.
716        iMBuff = cBuffer + iBeamSel;
717        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
718      }
719    }
720
721
722    if (cFlushing && cFlushBin == 0 && cFlushIF == 0 && cInterp) {
723      // Interpolate the beam position at the start of the flush cycle.
724#ifdef PKSIO_DEBUG
725      printf("Doing position interpolation for beam %d.\n", iMBuff->beamNo);
726#endif
727
728      double prevRA  = iMBuff->ra;
729      double prevDec = iMBuff->dec;
730      double prevUTC = cPosUTC[iBeamSel];
731
732      if (!cEOF && !cEOS) {
733        // The position is measured by the control system at a time returned
734        // by RPFITSIN as the 'w' visibility coordinate.  The ra and dec,
735        // returned as the 'u' and 'v' visibility coordinates, must be
736        // interpolated to the integration time which RPFITSIN returns as
737        // 'cUTC', this usually being a second or two later.
738        //
739        // Note that the time recorded as the 'w' visibility coordinate
740        // cycles through 86400 back to 0 at midnight, whereas that in 'cUTC'
741        // continues to increase past 86400.
742
743        double thisRA  = cU;
744        double thisDec = cV;
745        double thisUTC = cW;
746
747        if (thisUTC < prevUTC) {
748          // Must have cycled through midnight.
749          thisUTC += 86400.0;
750        }
751
752        // Guard against RA cycling through 24h in either direction.
753        if (fabs(thisRA - prevRA) > PI) {
754          if (thisRA < prevRA) {
755            thisRA += TWOPI;
756          } else {
757            thisRA -= TWOPI;
758          }
759        }
760
761        // The control system at Mopra typically does not update the
762        // positions between successive integration cycles at the end of a
763        // scan (nor are they flagged).  In this case we use the previously
764        // computed rates, even if from the previous scan since these are
765        // likely to be a better guess than anything else.
766
767        double dUTC = thisUTC - prevUTC;
768
769        // Scan rate for this beam.
770        if (dUTC > 0.0) {
771          iMBuff->raRate  = (thisRA  - prevRA)  / dUTC;
772          iMBuff->decRate = (thisDec - prevDec) / dUTC;
773
774          if (cInterp == 2) {
775            // Use the same interpolation scheme as the original pksmbfits
776            // client.  This incorrectly assumed that (thisUTC - prevUTC) is
777            // equal to the integration time and interpolated by computing a
778            // weighted sum of the positions before and after the required
779            // time.
780
781            double utc = iMBuff->utc;
782            if (utc - prevUTC > 100.0) {
783              // Must have cycled through midnight.
784              utc -= 86400.0;
785            }
786
787            double tw1 = 1.0 - (utc - prevUTC) / iMBuff->exposure;
788            double tw2 = 1.0 - (thisUTC - utc) / iMBuff->exposure;
789            double gamma = (tw2 / (tw1 + tw2)) * dUTC / (utc - prevUTC);
790
791            iMBuff->raRate  *= gamma;
792            iMBuff->decRate *= gamma;
793          }
794
795          cStaleness[iBeamSel] = 0;
796
797        } else {
798          // Issue warnings.
799          int nch = 0;
800          fprintf(stderr, "WARNING, scan %d,%n cycle %d: Position ",
801            iMBuff->scanNo, &nch, iMBuff->cycleNo);
802
803          if (dUTC < 0.0) {
804            fprintf(stderr, "timestamp went backwards!\n");
805          } else {
806            if (thisRA != prevRA || thisDec != prevDec) {
807              fprintf(stderr, "changed but timestamp unchanged!\n");
808            } else {
809              fprintf(stderr, "and timestamp unchanged!\n");
810            }
811          }
812
813          cStaleness[iBeamSel]++;
814          fprintf(stderr, "%-*s Using stale scan rate, staleness = %d "
815            "cycle%s.\n", nch, "WARNING,", cStaleness[iBeamSel],
816            (cStaleness[iBeamSel] == 1) ? "" : "s");
817
818          if (thisRA != prevRA || thisDec != prevDec) {
819            if (iMBuff->raRate == 0.0 && iMBuff->decRate == 0.0) {
820              fprintf(stderr, "%-*s But the previous rate was zero!  "
821                "Position will be inaccurate.\n", nch, "WARNING,");
822            }
823          }
824        }
825      }
826
827      // Compute the position of this beam for all bins.
828      for (int idx = 0; idx < cNBin; idx++) {
829        int jbuff = iBeamSel + cNBeamSel*idx;
830
831        cBuffer[jbuff].raRate  = iMBuff->raRate;
832        cBuffer[jbuff].decRate = iMBuff->decRate;
833
834        double dutc = cBuffer[jbuff].utc - prevUTC;
835        if (dutc > 100.0) {
836          // Must have cycled through midnight.
837          dutc -= 86400.0;
838        }
839
840        cBuffer[jbuff].ra  = prevRA  + cBuffer[jbuff].raRate  * dutc;
841        cBuffer[jbuff].dec = prevDec + cBuffer[jbuff].decRate * dutc;
842        if (cBuffer[jbuff].ra < 0.0) {
843          cBuffer[jbuff].ra += TWOPI;
844        } else if (cBuffer[jbuff].ra > TWOPI) {
845          cBuffer[jbuff].ra -= TWOPI;
846        }
847      }
848    }
849
850
851    if (cFlushing) {
852      // Copy buffer location out one IF at a time.
853      MBrec.extract(*iMBuff, cFlushIF);
854      haveData = 1;
855
856#ifdef PKSIO_DEBUG
857      printf("Out:%4d%4d%3d%3d\n", MBrec.scanNo, MBrec.cycleNo, MBrec.beamNo,
858        MBrec.IFno[0]);
859#endif
860
861      // Signal that this IF in this buffer location has been flushed.
862      iMBuff->IFno[cFlushIF] = 0;
863
864      if (cFlushIF == iMBuff->nIF - 1) {
865        // Signal that all IFs in this buffer location have been flushed.
866        iMBuff->nIF = 0;
867
868        // Stop cEOS being set when the next integration is read.
869        iMBuff->cycleNo = 0;
870
871      } else {
872        // Carry on flushing the other IFs.
873        continue;
874      }
875
876      // Has the whole buffer been flushed?
877      if (cFlushBin == cNBin - 1) {
878        if (cEOS || cEOF) {
879          // Carry on flushing other buffers.
880          cFlushIF = 0;
881          continue;
882        }
883
884        cFlushing = 0;
885
886        beamNo = int(cBaseline / 256.0);
887        iBeamSel = cBeamSel[beamNo-1];
888
889        // Compute buffer number.
890        iMBuff = cBuffer + iBeamSel;
891        if (cNBin > 1) iMBuff += cNBeamSel*(cBin-1);
892      }
893    }
894
895    if (!cFlushing) {
896      // Buffer this MBrec.
897      if (cCycleNo == 1 && iMBuff->IFno[0]) {
898        // Sanity check on the number of IFs in the new scan.
899        if (if_.n_if != cNIF) {
900          fprintf(stderr, "WARNING, scan %d has %d IFs instead of %d, "
901            "continuing.\n", cScanNo, if_.n_if, cNIF);
902        }
903      }
904
905      // Sanity check on incomplete integrations within a scan.
906      if (iMBuff->nIF && (iMBuff->cycleNo != cCycleNo)) {
907        // Force the incomplete integration to be flushed before proceeding.
908        cFlushing = 1;
909        continue;
910      }
911
912      iMBuff->scanNo  = cScanNo;
913      iMBuff->cycleNo = cCycleNo;
914
915      // Times.
916      strncpy(iMBuff->datobs, cDateObs, 10);
917      iMBuff->utc = cUTC;
918      iMBuff->exposure = param_.intbase;
919
920      // Source identification.
921      sprintf(iMBuff->srcName, "%-16.16s",
922              names_.su_name + (cSrcNo-1)*16);
923      iMBuff->srcRA  = doubles_.su_ra[cSrcNo-1];
924      iMBuff->srcDec = doubles_.su_dec[cSrcNo-1];
925
926      // Rest frequency of the line of interest.
927      iMBuff->restFreq = doubles_.rfreq;
928      if (strncmp(names_.instrument, "ATPKSMB", 7) == 0) {
929        // Fix the HI rest frequency recorded for Parkes multibeam data.
930        double reffreq  = doubles_.freq;
931        double restfreq = doubles_.rfreq;
932        if ((restfreq == 0.0 || fabs(restfreq - reffreq) == 0.0) &&
933             fabs(reffreq - 1420.40575e6) < 100.0) {
934          iMBuff->restFreq = 1420.40575e6;
935        }
936      }
937
938      // Observation type.
939      int j;
940      for (j = 0; j < 15; j++) {
941        iMBuff->obsType[j] = names_.card[11+j];
942        if (iMBuff->obsType[j] == '\'') break;
943      }
944      iMBuff->obsType[j] = '\0';
945
946      // Beam-dependent parameters.
947      iMBuff->beamNo = beamNo;
948
949      // Beam position at the specified time.
950      if (cSUpos) {
951        // Non-ATNF data that does not store the position in (u,v,w).
952        iMBuff->ra  = doubles_.su_ra[cSrcNo-1];
953        iMBuff->dec = doubles_.su_dec[cSrcNo-1];
954      } else {
955        iMBuff->ra  = cU;
956        iMBuff->dec = cV;
957      }
958      cPosUTC[iBeamSel] = cW;
959
960      // IF-dependent parameters.
961      int iIF = cIFno - 1;
962      int startChan = cStartChan[iIF];
963      int endChan   = cEndChan[iIF];
964      int refChan   = cRefChan[iIF];
965
966      int nChan = abs(endChan - startChan) + 1;
967
968      iIFSel = cIFSel[iIF];
969      iMBuff->nIF++;
970      iMBuff->IFno[iIFSel]  = cIFno;
971      iMBuff->nChan[iIFSel] = nChan;
972      iMBuff->nPol[iIFSel]  = cNPol[iIF];
973
974      iMBuff->fqRefPix[iIFSel] = doubles_.if_ref[iIF];
975      iMBuff->fqRefVal[iIFSel] = doubles_.if_freq[iIF];
976      iMBuff->fqDelt[iIFSel]   =
977        if_.if_invert[iIF] * fabs(doubles_.if_bw[iIF] /
978          (if_.if_nfreq[iIF] - 1));
979
980      // Adjust for channel selection.
981      if (iMBuff->fqRefPix[iIFSel] != refChan) {
982        iMBuff->fqRefVal[iIFSel] +=
983          (refChan - iMBuff->fqRefPix[iIFSel]) *
984            iMBuff->fqDelt[iIFSel];
985        iMBuff->fqRefPix[iIFSel] = refChan;
986      }
987
988      if (endChan < startChan) {
989        iMBuff->fqDelt[iIFSel] = -iMBuff->fqDelt[iIFSel];
990      }
991
992
993      // System temperature.
994      int iBeam = beamNo - 1;
995      int scq = sc_.sc_q;
996      float TsysPol1 = sc_.sc_cal[scq*iBeam + 3];
997      float TsysPol2 = sc_.sc_cal[scq*iBeam + 4];
998      iMBuff->tsys[iIFSel][0] = TsysPol1*TsysPol1;
999      iMBuff->tsys[iIFSel][1] = TsysPol2*TsysPol2;
1000
1001      // Calibration factor; may be changed later if the data is recalibrated.
1002      if (scq > 14) {
1003        // Will only be present for Parkes Multibeam or LBA data.
1004        iMBuff->calfctr[iIFSel][0] = sc_.sc_cal[scq*iBeam + 14];
1005        iMBuff->calfctr[iIFSel][1] = sc_.sc_cal[scq*iBeam + 15];
1006      } else {
1007        iMBuff->calfctr[iIFSel][0] = 0.0f;
1008        iMBuff->calfctr[iIFSel][1] = 0.0f;
1009      }
1010
1011      // Cross-polarization calibration factor (unknown to MBFITS).
1012      for (int j = 0; j < 2; j++) {
1013        iMBuff->xcalfctr[iIFSel][j] = 0.0f;
1014      }
1015
1016      // Baseline parameters (unknown to MBFITS).
1017      iMBuff->haveBase = 0;
1018
1019      // Data (always present in MBFITS).
1020      iMBuff->haveSpectra = 1;
1021
1022      // Flag:  bit 0 set if off source.
1023      //        bit 1 set if loss of sync in A polarization.
1024      //        bit 2 set if loss of sync in B polarization.
1025      unsigned char rpflag =
1026        (unsigned char)(sc_.sc_cal[scq*iBeam + 12] + 0.5f);
1027
1028      // The baseline flag may be set independently.
1029      if (rpflag == 0) rpflag = cFlag;
1030
1031      // Copy and scale data.
1032      int inc = 2 * if_.if_nstok[iIF];
1033      if (endChan < startChan) inc = -inc;
1034
1035      float TsysF;
1036      iMBuff->spectra[iIFSel] = iMBuff->spectra[0] + cChanOff[iIF];
1037      iMBuff->flagged[iIFSel] = iMBuff->flagged[0] + cChanOff[iIF];
1038
1039      float *spectra = iMBuff->spectra[iIFSel];
1040      unsigned char *flagged = iMBuff->flagged[iIFSel];
1041      for (int ipol = 0; ipol < cNPol[iIF]; ipol++) {
1042        if (sc_.sc_cal[scq*iBeam + 3 + ipol] > 0.0f) {
1043          // The correlator has already applied the calibration.
1044          TsysF = 1.0f;
1045        } else {
1046          // The correlator has normalized cVis[k] to a Tsys of 500K.
1047          TsysF = iMBuff->tsys[iIFSel][ipol] / 500.0f;
1048        }
1049
1050        int k = 2 * (if_.if_nstok[iIF]*(startChan - 1) + ipol);
1051        for (int ichan = 0; ichan < nChan; ichan++) {
1052          *(spectra++) = TsysF * cVis[k];
1053          *(flagged++) = rpflag;
1054          k += inc;
1055        }
1056      }
1057
1058      if (cHaveXPol[iIF]) {
1059        int k = 2 * (3*(startChan - 1) + 2);
1060        iMBuff->xpol[iIFSel] = iMBuff->xpol[0] + cXpolOff[iIF];
1061        float *xpol = iMBuff->xpol[iIFSel];
1062        for (int ichan = 0; ichan < nChan; ichan++) {
1063          *(xpol++) = cVis[k];
1064          *(xpol++) = cVis[k+1];
1065          k += inc;
1066        }
1067      }
1068
1069
1070      // Parallactic angle.
1071      iMBuff->parAngle = sc_.sc_cal[scq*iBeam + 11];
1072
1073      // Calibration factor applied to the data by the correlator.
1074      if (scq > 14) {
1075        // Will only be present for Parkes Multibeam or LBA data.
1076        iMBuff->tcal[iIFSel][0] = sc_.sc_cal[scq*iBeam + 14];
1077        iMBuff->tcal[iIFSel][1] = sc_.sc_cal[scq*iBeam + 15];
1078      } else {
1079        iMBuff->tcal[iIFSel][0] = 0.0f;
1080        iMBuff->tcal[iIFSel][1] = 0.0f;
1081      }
1082
1083      if (sc_.sc_ant <= anten_.nant) {
1084        // No extra syscal information present.
1085        iMBuff->extraSysCal = 0;
1086        iMBuff->azimuth   = 0.0f;
1087        iMBuff->elevation = 0.0f;
1088        iMBuff->parAngle  = 0.0f;
1089        iMBuff->focusAxi  = 0.0f;
1090        iMBuff->focusTan  = 0.0f;
1091        iMBuff->focusRot  = 0.0f;
1092        iMBuff->temp      = 0.0f;
1093        iMBuff->pressure  = 0.0f;
1094        iMBuff->humidity  = 0.0f;
1095        iMBuff->windSpeed = 0.0f;
1096        iMBuff->windAz    = 0.0f;
1097        strcpy(iMBuff->tcalTime, "                ");
1098        iMBuff->refBeam = 0;
1099
1100      } else {
1101        // Additional information for Parkes Multibeam data.
1102        int iOff = scq*(sc_.sc_ant - 1) - 1;
1103        iMBuff->extraSysCal = 1;
1104        iMBuff->azimuth   = sc_.sc_cal[iOff + 2];
1105        iMBuff->elevation = sc_.sc_cal[iOff + 3];
1106        iMBuff->parAngle  = sc_.sc_cal[iOff + 4];
1107        iMBuff->focusAxi  = sc_.sc_cal[iOff + 5] * 1e-3;
1108        iMBuff->focusTan  = sc_.sc_cal[iOff + 6] * 1e-3;
1109        iMBuff->focusRot  = sc_.sc_cal[iOff + 7];
1110        iMBuff->temp      = sc_.sc_cal[iOff + 8];
1111        iMBuff->pressure  = sc_.sc_cal[iOff + 9];
1112        iMBuff->humidity  = sc_.sc_cal[iOff + 10];
1113        iMBuff->windSpeed = sc_.sc_cal[iOff + 11];
1114        iMBuff->windAz    = sc_.sc_cal[iOff + 12];
1115
1116        char *tcalTime = iMBuff->tcalTime;
1117        sprintf(tcalTime, "%-16.16s", (char *)(&sc_.sc_cal[iOff+13]));
1118
1119#ifndef AIPS_LITTLE_ENDIAN
1120        // Do byte swapping on the ASCII date string.
1121        for (int j = 0; j < 16; j += 4) {
1122          char ctmp;
1123          ctmp = tcalTime[j];
1124          tcalTime[j]   = tcalTime[j+3];
1125          tcalTime[j+3] = ctmp;
1126          ctmp = tcalTime[j+1];
1127          tcalTime[j+1] = tcalTime[j+2];
1128          tcalTime[j+2] = ctmp;
1129        }
1130#endif
1131
1132        // Reference beam number.
1133        float refbeam = sc_.sc_cal[iOff + 17];
1134        if (refbeam > 0.0f || refbeam < 100.0f) {
1135          iMBuff->refBeam = int(refbeam);
1136        } else {
1137          iMBuff->refBeam = 0;
1138        }
1139      }
1140    }
1141  }
1142
1143  return 0;
1144}
1145
1146//-------------------------------------------------------- MBFITSreader::rpget
1147
1148// Read the next data record from the RPFITS file.
1149
1150int MBFITSreader::rpget(int syscalonly, int &EOS)
1151{
1152  EOS = 0;
1153
1154  int retries = 0;
1155
1156  // Allow 10 read errors.
1157  int numErr = 0;
1158
1159  int jstat = 0;
1160  while (numErr < 10) {
1161    int lastjstat = jstat;
1162    rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
1163              &cBin, &cIFno, &cSrcNo);
1164
1165    switch(jstat) {
1166    case -1:
1167      // Read failed; retry.
1168      numErr++;
1169      fprintf(stderr, "RPFITS read failed - retrying.\n");
1170      jstat = 0;
1171      break;
1172
1173    case 0:
1174      // Successful read.
1175      if (lastjstat == 0) {
1176        if (cBaseline == -1) {
1177          // Syscal data.
1178          if (syscalonly) {
1179            return 0;
1180          }
1181
1182        } else {
1183          if (!syscalonly) {
1184            return 0;
1185          }
1186        }
1187      }
1188
1189      // Last operation was to read header or FG table; now read data.
1190      break;
1191
1192    case 1:
1193      // Encountered header while trying to read data; read it.
1194      EOS = 1;
1195      jstat = -1;
1196      break;
1197
1198    case 2:
1199      // End of scan; read past it.
1200      jstat = 0;
1201      break;
1202
1203    case 3:
1204      // End-of-file; retry applies to real-time mode.
1205      if (retries++ >= cRetry) {
1206        return -1;
1207      }
1208
1209      sleep(10);
1210      jstat = 0;
1211      break;
1212
1213    case 4:
1214      // Encountered FG table while trying to read data; read it.
1215      jstat = -1;
1216      break;
1217
1218    case 5:
1219      // Illegal data at end of block after close/reopen operation; retry.
1220      jstat = 0;
1221      break;
1222
1223    default:
1224      // Shouldn't reach here.
1225      fprintf(stderr, "Unrecognized RPFITSIN return code: %d (retrying)\n",
1226              jstat);
1227      jstat = 0;
1228      break;
1229    }
1230  }
1231
1232  fprintf(stderr, "ERROR, RPFITS read failed too many times.\n");
1233  return 2;
1234}
1235
1236//-------------------------------------------------------- MBFITSreader::close
1237
1238// Close the input file.
1239
1240void MBFITSreader::close(void)
1241{
1242  if (cMBopen) {
1243    int jstat = 1;
1244    rpfitsin_(&jstat, cVis, cWgt, &cBaseline, &cUTC, &cU, &cV, &cW, &cFlag,
1245              &cBin, &cIFno, &cSrcNo);
1246
1247    if (cBeams)     delete [] cBeams;
1248    if (cIFs)       delete [] cIFs;
1249    if (cNChan)     delete [] cNChan;
1250    if (cNPol)      delete [] cNPol;
1251    if (cHaveXPol)  delete [] cHaveXPol;
1252    if (cStartChan) delete [] cStartChan;
1253    if (cEndChan)   delete [] cEndChan;
1254    if (cRefChan)   delete [] cRefChan;
1255
1256    if (cVis) delete [] cVis;
1257    if (cWgt) delete [] cWgt;
1258
1259    if (cBeamSel)   delete [] cBeamSel;
1260    if (cIFSel)     delete [] cIFSel;
1261    if (cChanOff)   delete [] cChanOff;
1262    if (cXpolOff)   delete [] cXpolOff;
1263    if (cBuffer)    delete [] cBuffer;
1264    if (cPosUTC)    delete [] cPosUTC;
1265
1266    cMBopen = 0;
1267  }
1268}
Note: See TracBrowser for help on using the repository browser.