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

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

sync with livedata/implement/atnf

File size: 36.8 KB
RevLine 
[1325]1//#---------------------------------------------------------------------------
2//# MBFITSreader.cc: ATNF single-dish RPFITS reader.
3//#---------------------------------------------------------------------------
[1427]4//# Copyright (C) 2000-2008
[1325]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//#
[1427]29//# $Id: MBFITSreader.cc,v 19.38 2008-06-26 02:24:22 cal103 Exp $
[1325]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;
[1427]54const double R2D = 180.0 / PI;
[1325]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) {
[1372]135 fprintf(stderr, "ERROR, failed to open MBFITS file: %s\n", rpname);
[1325]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) {
[1372]155 fprintf(stderr, "ERROR, failed to read MBFITS header: %s\n", rpname);
[1325]156 close();
157 return 1;
158 }
159
160 // Mopra data has some peculiarities.
161 cMopra = strncmp(names_.instrument, "ATMOPRA", 7) == 0;
162
[1372]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");
[1325]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) {
[1372]192 fprintf(stderr, "ERROR, couldn't determine number of beams.\n");
[1325]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)) {
[1372]294 fprintf(stderr, "ERROR, failed to read first syscal record.\n");
[1325]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],
[1399]320 char bunit[32],
[1325]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) {
[1372]330 fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
[1325]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
[1399]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
[1325]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) {
[1372]460 fprintf(stderr, "ERROR, an MBFITS file has not been opened.\n");
[1325]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
[1427]504 printf("\nEnd-of-file detected, flushing last scan.\n");
[1325]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) {
[1372]588 fprintf(stderr, "ERROR, cannot handle binning mode for multiple "
[1325]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
[1399]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
[1325]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
[1427]669 printf("\n In:%4d%4d%3d%3d\n", cScanNo, cCycleNo, beamNo, cIFno);
[1325]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) {
[1427]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.
[1325]755
[1427]756 double thisRA = iMBuff->ra;
757 double thisDec = iMBuff->dec;
758 double thisUTC = cPosUTC[iBeamSel];
[1325]759
[1427]760 if (cEOF || cEOS) {
761 iMBuff->rateAge++;
762 iMBuff->rateson = 0;
763
764 } else {
[1325]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
[1427]769 double nextRA = cU;
770 double nextDec = cV;
771 double nextUTC = cW;
[1325]772
[1427]773 if (nextUTC < thisUTC) {
[1325]774 // Must have cycled through midnight.
[1427]775 nextUTC += 86400.0;
[1325]776 }
777
778 // Guard against RA cycling through 24h in either direction.
[1427]779 if (fabs(nextRA - thisRA) > PI) {
780 if (nextRA < thisRA) {
781 nextRA += TWOPI;
[1325]782 } else {
[1427]783 nextRA -= TWOPI;
[1325]784 }
785 }
786
[1427]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
[1325]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
[1427]800 double dUTC = nextUTC - thisUTC;
[1325]801
802 // Scan rate for this beam.
803 if (dUTC > 0.0) {
[1427]804 iMBuff->raRate = (nextRA - thisRA) / dUTC;
805 iMBuff->decRate = (nextDec - thisDec) / dUTC;
806 iMBuff->rateAge = 0;
807 iMBuff->rateson = 0;
[1325]808
809 if (cInterp == 2) {
810 // Use the same interpolation scheme as the original pksmbfits
[1427]811 // client. This incorrectly assumed that (nextUTC - thisUTC) is
[1325]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;
[1427]817 if (utc - thisUTC > 100.0) {
[1325]818 // Must have cycled through midnight.
819 utc -= 86400.0;
820 }
821
[1427]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);
[1325]825
826 iMBuff->raRate *= gamma;
827 iMBuff->decRate *= gamma;
828 }
829
830 } else {
[1427]831 iMBuff->rateAge++;
[1325]832
[1427]833 // Staleness codes.
[1325]834 if (dUTC < 0.0) {
[1427]835 iMBuff->rateson = 3;
[1325]836 } else {
[1427]837 if (nextRA != thisRA || nextDec != thisDec) {
838 iMBuff->rateson = 2;
[1325]839 } else {
[1427]840 iMBuff->rateson = 1;
[1325]841 }
842 }
843 }
844 }
845
[1427]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
[1325]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
[1427]859 double dutc = cBuffer[jbuff].utc - thisUTC;
[1325]860 if (dutc > 100.0) {
861 // Must have cycled through midnight.
862 dutc -= 86400.0;
863 }
864
[1427]865 cBuffer[jbuff].ra = thisRA + cBuffer[jbuff].raRate * dutc;
866 cBuffer[jbuff].dec = thisDec + cBuffer[jbuff].decRate * dutc;
[1325]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.
[1399]922 if ((cScanNo > iMBuff->scanNo) && iMBuff->IFno[0]) {
[1325]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
[1372]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
[1325]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.
[1372]975 if (cSUpos) {
976 // Non-ATNF data that does not store the position in (u,v,w).
[1325]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
[1372]1257 fprintf(stderr, "ERROR, RPFITS read failed too many times.\n");
[1325]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.