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

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

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

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