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

Last change on this file since 1400 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.