source: trunk/external/atnf/PKSIO/MBFITSreader.cc @ 1325

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

Changes to use casacore instead of casa_asap/aips++\nAdded atnf PKSIO library snapshot to external and linking against this local copy

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