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

Last change on this file since 1427 was 1427, checked in by Malte Marquarding, 16 years ago

sync with livedata/implement/atnf

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