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

Last change on this file since 1399 was 1399, checked in by Malte Marquarding, 17 years ago

Mark C added brightness unit to getHeader()

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