source: branches/alma/external/atnf/PKSIO/MBFITSreader.cc@ 1721

Last change on this file since 1721 was 1453, checked in by TakTsutsumi, 16 years ago

New Development: No

JIRA Issue: No

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: many

Test Programs: sd.scantable(), sd.scantable.save()

Put in Release Notes: N/A

Description: copied from current casapy code tree


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