source: trunk/src/MSWriter.cpp @ 2842

Last change on this file since 2842 was 2842, checked in by Takeshi Nakazato, 11 years ago

New Development: No

JIRA Issue: Yes CAS-5545

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: test_sdsave[sdsave_flagging]

Put in Release Notes: No

Module(s): sd

Description: Describe your changes here...

Changed a behavior of MSWriter according to CAS-5545.

  • All the FLAG_ROW's are always set to False.
  • If FLAGROW is non-zero in a certain Scantable row, all the FLAG values in the corresponding location in MS/MAIN (FLAG in the corresponding polarization component) have to be set to True.


File size: 79.1 KB
Line 
1//
2// C++ Interface: MSWriter
3//
4// Description:
5//
6// This class is specific writer for MS format
7//
8// Takeshi Nakazato <takeshi.nakazato@nao.ac.jp>, (C) 2010
9//
10// Copyright: See COPYING file that comes with this distribution
11//
12//
13#include <assert.h>
14
15#include <set>
16
17#include <casa/OS/File.h>
18#include <casa/OS/RegularFile.h>
19#include <casa/OS/Directory.h>
20#include <casa/OS/SymLink.h>
21#include <casa/BasicSL/String.h>
22#include <casa/Arrays/Cube.h>
23#include <casa/Containers/RecordField.h>
24
25#include <tables/Tables/ExprNode.h>
26#include <tables/Tables/TableDesc.h>
27#include <tables/Tables/SetupNewTab.h>
28#include <tables/Tables/TableIter.h>
29#include <tables/Tables/RefRows.h>
30#include <tables/Tables/TableRow.h>
31
32#include <ms/MeasurementSets/MeasurementSet.h>
33#include <ms/MeasurementSets/MSColumns.h>
34#include <ms/MeasurementSets/MSPolIndex.h>
35#include <ms/MeasurementSets/MSDataDescIndex.h>
36#include <ms/MeasurementSets/MSSourceIndex.h>
37
38#include "MSWriter.h"
39#include "STHeader.h"
40#include "STFrequencies.h"
41#include "STMolecules.h"
42#include "STTcal.h"
43#include "MathUtils.h"
44#include "TableTraverse.h"
45
46using namespace casa ;
47using namespace std ;
48
49namespace asap {
50
51class CorrTypeHandler {
52public:
53  CorrTypeHandler()
54  {}
55  virtual ~CorrTypeHandler() {}
56  virtual Vector<Stokes::StokesTypes> corrType() = 0 ;
57  virtual void reset()
58  {
59    npol = 0 ;
60  }
61  void append( uInt polno )
62  {
63    polnos[npol] = polno ;
64    npol++ ;
65  }
66  uInt nPol() { return npol ; }
67protected:
68  Vector<Stokes::StokesTypes> polmap ;
69  uInt polnos[4] ;
70  uInt npol ;
71};
72
73class LinearHandler : public CorrTypeHandler {
74public:
75  LinearHandler()
76    : CorrTypeHandler()
77  {
78    initMap() ;
79  }
80  virtual ~LinearHandler() {}
81  virtual Vector<Stokes::StokesTypes> corrType()
82  {
83    Vector<Stokes::StokesTypes> ret( npol, Stokes::Undefined ) ;
84    if ( npol < 4 ) {
85      for ( uInt ipol = 0 ; ipol < npol ; ipol++ )
86        ret[ipol] = polmap[polnos[ipol]] ;
87    }
88    else if ( npol == 4 ) {
89      ret[0] = polmap[0] ;
90      ret[1] = polmap[2] ;
91      ret[2] = polmap[3] ;
92      ret[3] = polmap[1] ;
93    }
94    else {
95      throw( AipsError("npol > 4") ) ;
96    }
97    return ret ;
98  }
99protected:
100  void initMap()
101  {
102    polmap.resize( 4 ) ;
103    polmap[0] = Stokes::XX ;
104    polmap[1] = Stokes::YY ;
105    polmap[2] = Stokes::XY ;
106    polmap[3] = Stokes::YX ;
107  }
108};
109class CircularHandler : public CorrTypeHandler {
110public:
111  CircularHandler()
112    : CorrTypeHandler()
113  {
114    initMap() ;
115  }
116  virtual ~CircularHandler() {}
117  virtual Vector<Stokes::StokesTypes> corrType()
118  {
119    Vector<Stokes::StokesTypes> ret( npol, Stokes::Undefined ) ;
120    if ( npol < 4 ) {
121      for ( uInt ipol = 0 ; ipol < npol ; ipol++ )
122        ret[ipol] = polmap[polnos[ipol]] ;
123    }
124    else if ( npol == 4 ) {
125      ret[0] = polmap[0] ;
126      ret[1] = polmap[2] ;
127      ret[2] = polmap[3] ;
128      ret[3] = polmap[1] ;
129    }
130    else {
131      throw( AipsError("npol > 4") ) ;
132    }
133    return ret ;
134  }
135private:
136  void initMap()
137  {
138    polmap.resize( 4 ) ;
139    polmap[0] = Stokes::RR ;
140    polmap[1] = Stokes::LL ;
141    polmap[2] = Stokes::RL ;
142    polmap[3] = Stokes::LR ;
143  }
144};
145class StokesHandler : public CorrTypeHandler {
146public:
147  StokesHandler()
148    : CorrTypeHandler()
149  {
150    initMap() ;
151  }
152  virtual ~StokesHandler() {}
153  virtual Vector<Stokes::StokesTypes> corrType()
154  {
155    Vector<Stokes::StokesTypes> ret( npol, Stokes::Undefined ) ;
156    if ( npol <= 4 ) {
157      for ( uInt ipol = 0 ; ipol < npol ; ipol++ )
158        ret[ipol] = polmap[polnos[ipol]] ;
159    }
160    else {
161      throw( AipsError("npol > 4") ) ;
162    }
163    return ret ;
164  }
165private:
166  void initMap()
167  {
168    polmap.resize( 4 ) ;
169    polmap[0] = Stokes::I ;
170    polmap[1] = Stokes::Q ;
171    polmap[2] = Stokes::U ;
172    polmap[3] = Stokes::V ;
173  }
174};
175class LinPolHandler : public CorrTypeHandler {
176public:
177  LinPolHandler()
178    : CorrTypeHandler()
179  {
180    initMap() ;
181  }
182  virtual ~LinPolHandler() {}
183  virtual Vector<Stokes::StokesTypes> corrType()
184  {
185    Vector<Stokes::StokesTypes> ret( npol, Stokes::Undefined ) ;
186    if ( npol <= 2 ) {
187      for ( uInt ipol = 0 ; ipol < npol ; ipol++ )
188        ret[ipol] = polmap[polnos[ipol]] ;
189    }
190    else {
191      throw( AipsError("npol > 4") ) ;
192    }
193    return ret ;
194  }
195private:
196  void initMap()
197  {
198    polmap.resize( 2 ) ;
199    polmap[0] = Stokes::Plinear ;
200    polmap[1] = Stokes::Pangle ;
201  }
202};
203
204class DataHolder {
205public:
206  DataHolder( TableRow &tableRow, String polType )
207    : row( tableRow )
208  {
209    nchan = 0 ;
210    npol = 0 ;
211    makeCorrTypeHandler( polType ) ;
212    attach() ;
213    flagRow.resize( 4 ) ;
214    reset() ;
215    sigmaTemplate.resize( 4 ) ;
216    sigmaTemplate = 1.0 ;
217  }
218  virtual ~DataHolder() {}
219  void post()
220  {
221    postData() ;
222    postFlag() ;
223    postFlagRow() ;
224    postAuxiliary() ;
225  }
226  virtual void reset()
227  {
228    corr->reset() ;
229    flagRow = False ;
230    npol = 0 ;
231    for ( uInt i = 0 ; i < 4 ; i++ )
232      isFilled[i] = False ;   
233  }
234  virtual void accumulate( uInt id, Vector<Float> &sp, Vector<Bool> &fl, Bool &flr )
235  {
236    accumulateCorrType( id ) ;
237    accumulateData( id, sp ) ;
238    accumulateFlag( id, fl ) ;
239    accumulateFlagRow( id, flr ) ;
240    isFilled[id] = True;
241  }
242  uInt nPol() { return npol ; }
243  uInt nChan() { return nchan ; }
244  Vector<Int> corrTypeInt()
245  {
246    Vector<Int> v( npol ) ;
247    convertArray( v, corr->corrType() ) ;
248    return v ;
249  }
250  Vector<Stokes::StokesTypes> corrType() { return corr->corrType() ; }
251  void setNchan( uInt num )
252  {
253    nchan = num ;
254    resize() ;
255  }
256protected:
257  void postAuxiliary()
258  {
259    Vector<Float> w = sigmaTemplate( IPosition(1,0), IPosition(1,npol-1) ) ;
260    sigmaRF.define( w ) ;
261    weightRF.define( w ) ;
262    Cube<Bool> c( npol, nchan, 1, False ) ;
263    flagCategoryRF.define( c ) ;
264  }
265  inline void accumulateCorrType( uInt &id )
266  {
267    corr->append( id ) ;
268    npol = corr->nPol() ;
269  }
270  inline void accumulateFlagRow( uInt &id, Bool &flr )
271  {
272    flagRow[id] = flr ;
273  }
274  void postFlagRow()
275  {
276    // CAS-5545 FLAG_ROW must always be set False
277    //*flagRowRF = anyEQ( flagRow, True ) ;
278    *flagRowRF = False;
279  }
280  inline void accumulateFlag( uInt &id, Vector<Bool> &fl )
281  {
282    flag.row( id ) = fl ;
283  }
284  virtual void postFlag() = 0 ;
285  inline void accumulateData( uInt &id, Vector<Float> &sp )
286  {
287    data.row( id ) = sp ;
288  }
289  uInt filledIndex()
290  {
291    uInt idx = 0;
292    while( !isFilled[idx] && idx < 4 ) ++idx;
293    return idx;
294  }
295  virtual void postData() = 0 ;
296  TableRow &row ;
297  uInt nchan ;
298  uInt npol ;
299  CountedPtr<CorrTypeHandler> corr;
300  RecordFieldPtr< Vector<Float> > sigmaRF ;
301  RecordFieldPtr< Vector<Float> > weightRF ;
302  RecordFieldPtr< Array<Bool> > flagRF ;
303  RecordFieldPtr<Bool> flagRowRF ;
304  RecordFieldPtr< Cube<Bool> > flagCategoryRF ;
305  Vector<Bool> flagRow ;
306  Matrix<Bool> flag ;
307  Matrix<Float> data ;
308  Vector<Float> sigmaTemplate ;
309  Bool isFilled[4] ;
310private:
311  void makeCorrTypeHandler( String &polType )
312  {
313    if ( polType == "linear" )
314      corr = new LinearHandler() ;
315    else if ( polType == "circular" )
316      corr = new CircularHandler() ;
317    else if ( polType == "stokes" )
318      corr = new StokesHandler() ;
319    else if ( polType == "linpol" )
320      corr = new LinPolHandler() ;
321    else
322      throw( AipsError("Invalid polarization type") ) ;
323  }
324  void attach()
325  {
326    TableRecord &rec = row.record() ;
327    sigmaRF.attachToRecord( rec, "SIGMA" ) ;
328    weightRF.attachToRecord( rec, "WEIGHT" ) ;
329    flagRF.attachToRecord( rec, "FLAG" ) ;
330    flagRowRF.attachToRecord( rec, "FLAG_ROW" ) ;
331    flagCategoryRF.attachToRecord( rec, "FLAG_CATEGORY" ) ;
332  }
333  void resize()
334  {
335    flag.resize( 4, nchan ) ;
336    data.resize( 4, nchan ) ;
337  }
338};
339
340class FloatDataHolder : public DataHolder {
341public:
342  FloatDataHolder( TableRow &tableRow, String polType )
343    : DataHolder( tableRow, polType )
344  {
345    attachData() ;
346  }
347  virtual ~FloatDataHolder() {}
348protected:
349  virtual void postFlag()
350  {
351    // CAS-5545 FLAG must all be set True if FLAG_ROW is True
352    for (uInt ipol = 0; ipol < npol; ++ipol) {
353      if (flagRow[ipol]) {
354        flag(IPosition(2, ipol, 0), IPosition(2, ipol, nchan-1)) = True;
355      }
356    }
357   
358    if ( npol == 2 ) {
359      flagRF.define( flag( IPosition( 2, 0, 0 ), IPosition( 2, npol-1, nchan-1 ) ) ) ;
360    }
361    else {
362      // should be npol == 1
363      uInt idx = filledIndex() ;
364      flagRF.define( flag( IPosition( 2, idx, 0 ), IPosition( 2, idx, nchan-1 ) ) ) ;
365    }
366  }
367  virtual void postData()
368  {
369    if ( npol == 2 ) {
370      dataRF.define( data( IPosition( 2, 0, 0 ), IPosition( 2, npol-1, nchan-1 ) ) ) ;
371    }
372    else {
373      // should be npol == 1
374      uInt idx = filledIndex() ;
375      dataRF.define( data( IPosition( 2, idx, 0 ), IPosition( 2, idx, nchan-1 ) ) ) ;
376    }
377  }
378private:
379  void attachData()
380  {
381    dataRF.attachToRecord( row.record(), "FLOAT_DATA" ) ;
382  }
383  RecordFieldPtr< Matrix<Float> > dataRF;
384};
385
386class ComplexDataHolder : public DataHolder {
387public:
388  ComplexDataHolder( TableRow &tableRow, String polType )
389    : DataHolder( tableRow, polType )
390  {
391    attachData() ;
392  }
393  virtual ~ComplexDataHolder() {}
394protected:
395  virtual void postFlag()
396  {
397    // CAS-5545 FLAG must all be set True if FLAG_ROW is True
398    for (uInt ipol = 0; ipol < npol; ++ipol) {
399      if (flagRow[ipol]) {
400        flag(IPosition(2, ipol, 0), IPosition(2, ipol, nchan-1)) = True;
401      }
402    }
403   
404    if ( npol == 4 ) {
405      Vector<Bool> tmp = flag.row( 3 ) ;
406      flag.row( 3 ) = flag.row( 1 ) ;
407      flag.row( 2 ) = flag.row( 2 ) || tmp ;
408      flag.row( 1 ) = flag.row( 2 ) ;
409      flagRF.define( flag ) ;
410    }
411    else if ( npol == 2 ) {
412      flagRF.define( flag( IPosition( 2, 0, 0 ), IPosition( 2, npol-1, nchan-1 ) ) ) ;
413    }
414    else {
415      // should be npol == 1
416      uInt idx = filledIndex() ;
417      flagRF.define( flag( IPosition( 2, idx, 0 ), IPosition( 2, idx, nchan-1 ) ) ) ;
418    }
419  }
420  virtual void postData()
421  {
422    Matrix<Float> tmp( 2, nchan, 0.0 ) ;
423    Matrix<Complex> v( npol, nchan ) ;
424    if ( isFilled[0] ) {
425      tmp.row( 0 ) = data.row( 0 ) ;
426      v.row( 0 ) = RealToComplex( tmp ) ;
427    }
428    if ( isFilled[1] ) {
429      tmp.row( 0 ) = data.row( 1 ) ;
430      v.row( npol-1 ) = RealToComplex( tmp ) ;
431    }
432    if ( isFilled[2] && isFilled[3] ) {
433      tmp.row( 0 ) = data.row( 2 ) ;
434      tmp.row( 1 ) = data.row( 3 ) ;
435      v.row( 1 ) = RealToComplex( tmp ) ;
436      v.row( 2 ) = conj( v.row( 1 ) ) ;
437    }
438    dataRF.define( v ) ;
439  }
440private:
441  void attachData()
442  {
443    dataRF.attachToRecord( row.record(), "DATA" ) ;
444  }
445  RecordFieldPtr< Matrix<Complex> > dataRF;
446};
447
448class BaseMSWriterVisitor: public TableVisitor {
449  const String *lastFieldName;
450  uInt lastRecordNo;
451  uInt lastBeamNo, lastScanNo, lastIfNo, lastPolNo;
452  Int lastSrcType;
453  uInt lastCycleNo;
454  Double lastTime;
455protected:
456  const Table &table;
457  uInt count;
458public:
459  BaseMSWriterVisitor(const Table &table)
460    : table(table)
461  {
462    static const String dummy;
463    lastFieldName = &dummy;
464    count = 0;
465  }
466 
467  virtual void enterFieldName(const uInt /*recordNo*/, const String &/*columnValue*/) {
468  }
469  virtual void leaveFieldName(const uInt /*recordNo*/, const String &/*columnValue*/) {
470  }
471  virtual void enterBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
472  virtual void leaveBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
473  virtual void enterScanNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
474  virtual void leaveScanNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
475  virtual void enterIfNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
476  virtual void leaveIfNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
477  virtual void enterSrcType(const uInt /*recordNo*/, Int /*columnValue*/) { }
478  virtual void leaveSrcType(const uInt /*recordNo*/, Int /*columnValue*/) { }
479  virtual void enterCycleNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
480  virtual void leaveCycleNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
481  virtual void enterTime(const uInt /*recordNo*/, Double /*columnValue*/) { }
482  virtual void leaveTime(const uInt /*recordNo*/, Double /*columnValue*/) { }
483  virtual void enterPolNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
484  virtual void leavePolNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
485
486  virtual Bool visitRecord(const uInt /*recordNo*/,
487                           const String &/*fieldName*/,
488                           const uInt /*beamNo*/,
489                           const uInt /*scanNo*/,
490                           const uInt /*ifNo*/,
491                           const Int /*srcType*/,
492                           const uInt /*cycleNo*/,
493                           const Double /*time*/,
494                           const uInt /*polNo*/) { return True ;}
495
496  virtual Bool visit(Bool isFirst, const uInt recordNo,
497                     const uInt nCols, void const *const colValues[]) {
498    const String *fieldName = NULL;
499    uInt beamNo, scanNo, ifNo;
500    Int srcType;
501    uInt cycleNo;
502    Double time;
503    uInt polNo;
504    { // prologue
505      uInt i = 0;
506      {
507        const String *col = (const String*)colValues[i++];
508        fieldName = &col[recordNo];
509      }
510      {
511        const uInt *col = (const uInt *)colValues[i++];
512        beamNo = col[recordNo];
513      }
514      {
515        const uInt *col = (const uInt *)colValues[i++];
516        scanNo = col[recordNo];
517      }
518      {
519        const uInt *col = (const uInt *)colValues[i++];
520        ifNo = col[recordNo];
521      }
522      {
523        const Int *col = (const Int *)colValues[i++];
524        srcType = col[recordNo];
525      }
526      {
527        const uInt *col = (const uInt *)colValues[i++];
528        cycleNo = col[recordNo];
529      }
530      {
531        const Double *col = (const Double *)colValues[i++];
532        time = col[recordNo];
533      }
534      {
535        const Int *col = (const Int *)colValues[i++];
536        polNo = col[recordNo];
537      }
538      assert(nCols == i);
539    }
540
541    if (isFirst) {
542      enterFieldName(recordNo, *fieldName);
543      enterBeamNo(recordNo, beamNo);
544      enterScanNo(recordNo, scanNo);
545      enterIfNo(recordNo, ifNo);
546      enterSrcType(recordNo, srcType);
547      enterCycleNo(recordNo, cycleNo);
548      enterTime(recordNo, time);
549      enterPolNo(recordNo, polNo);
550    } else {
551      if (lastFieldName->compare(*fieldName) != 0) {
552        leavePolNo(lastRecordNo, lastPolNo);
553        leaveTime(lastRecordNo, lastTime);
554        leaveCycleNo(lastRecordNo, lastCycleNo);
555        leaveSrcType(lastRecordNo, lastSrcType);
556        leaveIfNo(lastRecordNo, lastIfNo);
557        leaveScanNo(lastRecordNo, lastScanNo);
558        leaveBeamNo(lastRecordNo, lastBeamNo);
559        leaveFieldName(lastRecordNo, *lastFieldName);
560
561        enterFieldName(recordNo, *fieldName);
562        enterBeamNo(recordNo, beamNo);
563        enterScanNo(recordNo, scanNo);
564        enterIfNo(recordNo, ifNo);
565        enterSrcType(recordNo, srcType);
566        enterCycleNo(recordNo, cycleNo);
567        enterTime(recordNo, time);
568        enterPolNo(recordNo, polNo);
569      } else if (lastBeamNo != beamNo) {
570        leavePolNo(lastRecordNo, lastPolNo);
571        leaveTime(lastRecordNo, lastTime);
572        leaveCycleNo(lastRecordNo, lastCycleNo);
573        leaveSrcType(lastRecordNo, lastSrcType);
574        leaveIfNo(lastRecordNo, lastIfNo);
575        leaveScanNo(lastRecordNo, lastScanNo);
576        leaveBeamNo(lastRecordNo, lastBeamNo);
577
578        enterBeamNo(recordNo, beamNo);
579        enterScanNo(recordNo, scanNo);
580        enterIfNo(recordNo, ifNo);
581        enterSrcType(recordNo, srcType);
582        enterCycleNo(recordNo, cycleNo);
583        enterTime(recordNo, time);
584        enterPolNo(recordNo, polNo);
585      } else if (lastScanNo != scanNo) {
586        leavePolNo(lastRecordNo, lastPolNo);
587        leaveTime(lastRecordNo, lastTime);
588        leaveCycleNo(lastRecordNo, lastCycleNo);
589        leaveSrcType(lastRecordNo, lastSrcType);
590        leaveIfNo(lastRecordNo, lastIfNo);
591        leaveScanNo(lastRecordNo, lastScanNo);
592
593        enterScanNo(recordNo, scanNo);
594        enterIfNo(recordNo, ifNo);
595        enterSrcType(recordNo, srcType);
596        enterCycleNo(recordNo, cycleNo);
597        enterTime(recordNo, time);
598        enterPolNo(recordNo, polNo);
599      } else if (lastIfNo != ifNo) {
600        leavePolNo(lastRecordNo, lastPolNo);
601        leaveTime(lastRecordNo, lastTime);
602        leaveCycleNo(lastRecordNo, lastCycleNo);
603        leaveSrcType(lastRecordNo, lastSrcType);
604        leaveIfNo(lastRecordNo, lastIfNo);
605
606        enterIfNo(recordNo, ifNo);
607        enterSrcType(recordNo, srcType);
608        enterCycleNo(recordNo, cycleNo);
609        enterTime(recordNo, time);
610        enterPolNo(recordNo, polNo);
611      } else if (lastSrcType != srcType) {
612        leavePolNo(lastRecordNo, lastPolNo);
613        leaveTime(lastRecordNo, lastTime);
614        leaveCycleNo(lastRecordNo, lastCycleNo);
615        leaveSrcType(lastRecordNo, lastSrcType);
616
617        enterSrcType(recordNo, srcType);
618        enterCycleNo(recordNo, cycleNo);
619        enterTime(recordNo, time);
620        enterPolNo(recordNo, polNo);
621      } else if (lastCycleNo != cycleNo) {
622        leavePolNo(lastRecordNo, lastPolNo);
623        leaveTime(lastRecordNo, lastTime);
624        leaveCycleNo(lastRecordNo, lastCycleNo);
625
626        enterCycleNo(recordNo, cycleNo);
627        enterTime(recordNo, time);
628        enterPolNo(recordNo, polNo);
629      } else if (lastTime != time) {
630        leavePolNo(lastRecordNo, lastPolNo);
631        leaveTime(lastRecordNo, lastTime);
632
633        enterTime(recordNo, time);
634        enterPolNo(recordNo, polNo);
635      } else if (lastPolNo != polNo) {
636        leavePolNo(lastRecordNo, lastPolNo);
637        enterPolNo(recordNo, polNo);
638      }
639    }
640    count++;
641    Bool result = visitRecord(recordNo, *fieldName, beamNo, scanNo, ifNo, srcType,
642                              cycleNo, time, polNo);
643
644    { // epilogue
645      lastRecordNo = recordNo;
646
647      lastFieldName = fieldName;
648      lastBeamNo = beamNo;
649      lastScanNo = scanNo;
650      lastIfNo = ifNo;
651      lastSrcType = srcType;
652      lastCycleNo = cycleNo;
653      lastTime = time;
654      lastPolNo = polNo;
655    }
656    return result ;
657  }
658
659  virtual void finish() {
660    if (count > 0) {
661      leavePolNo(lastRecordNo, lastPolNo);
662      leaveTime(lastRecordNo, lastTime);
663      leaveCycleNo(lastRecordNo, lastCycleNo);
664      leaveSrcType(lastRecordNo, lastSrcType);
665      leaveIfNo(lastRecordNo, lastIfNo);
666      leaveScanNo(lastRecordNo, lastScanNo);
667      leaveBeamNo(lastRecordNo, lastBeamNo);
668      leaveFieldName(lastRecordNo, *lastFieldName);
669    }
670  }
671};
672
673class MSWriterVisitor: public BaseMSWriterVisitor, public MSWriterUtils {
674public:
675  MSWriterVisitor(const Table &table, Table &mstable)
676    : BaseMSWriterVisitor(table),
677      ms(mstable)
678  {
679    rowidx = 0 ;
680    fieldName = "" ;
681    defaultFieldId = 0 ;
682    spwId = -1 ;
683    subscan = 1 ;
684    ptName = "" ;
685    srcId = 0 ;
686   
687    row = TableRow( ms ) ;
688
689    initPolarization() ;
690    initFrequencies() ;
691
692    //
693    // add rows to MS
694    //
695    uInt addrow = table.nrow() ;
696    ms.addRow( addrow ) ;
697
698    // attach to Scantable columns
699    spectraCol.attach( table, "SPECTRA" ) ;
700    flagtraCol.attach( table, "FLAGTRA" ) ;
701    flagRowCol.attach( table, "FLAGROW" ) ;
702    tcalIdCol.attach( table, "TCAL_ID" ) ;
703    intervalCol.attach( table, "INTERVAL" ) ;
704    directionCol.attach( table, "DIRECTION" ) ;
705    scanRateCol.attach( table, "SCANRATE" ) ;
706    timeCol.attach( table, "TIME" ) ;
707    freqIdCol.attach( table, "FREQ_ID" ) ;
708    sourceNameCol.attach( table, "SRCNAME" ) ;
709    sourceDirectionCol.attach( table, "SRCDIRECTION" ) ;
710    fieldNameCol.attach( table, "FIELDNAME" ) ;
711
712    // MS subtables
713    attachSubtables() ;
714
715    // attach to MS columns
716    attachMain() ;
717    attachPointing() ;
718  }
719 
720  virtual void enterFieldName(const uInt recordNo, const String &/*columnValue*/) {
721    //printf("%u: FieldName: %s\n", recordNo, columnValue.c_str());
722    fieldName = fieldNameCol.asString( recordNo ) ;
723    String::size_type pos = fieldName.find( "__" ) ;
724    if ( pos != String::npos ) {
725      fieldId = String::toInt( fieldName.substr( pos+2 ) ) ;
726      fieldName = fieldName.substr( 0, pos ) ;
727    }
728    else {
729      fieldId = defaultFieldId ;
730      defaultFieldId++ ;
731    }
732    Double tSec = timeCol.asdouble( recordNo ) * 86400.0 ;
733    Vector<Double> srcDir = sourceDirectionCol( recordNo ) ;
734    Vector<Double> srate = scanRateCol( recordNo ) ;
735    String srcName = sourceNameCol.asString( recordNo ) ;
736
737    addField( fieldId, fieldName, srcName, srcDir, srate, tSec ) ;
738
739    // put value
740    *fieldIdRF = fieldId ;
741  }
742  virtual void leaveFieldName(const uInt /*recordNo*/, const String &/*columnValue*/) {
743  }
744  virtual void enterBeamNo(const uInt /*recordNo*/, uInt columnValue) {
745    //printf("%u: BeamNo: %u\n", recordNo, columnValue);
746   
747    feedId = (Int)columnValue ;
748
749    // put value
750    *feed1RF = feedId ;
751    *feed2RF = feedId ;
752  }
753  virtual void leaveBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
754  }
755  virtual void enterScanNo(const uInt /*recordNo*/, uInt columnValue) {
756    //printf("%u: ScanNo: %u\n", recordNo, columnValue);
757
758    // put value
759    // SCAN_NUMBER is 0-based in Scantable while 1-based in MS
760    *scanNumberRF = (Int)columnValue + 1 ;
761  }
762  virtual void leaveScanNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
763    subscan = 1 ;
764  }
765  virtual void enterIfNo(const uInt recordNo, uInt columnValue) {
766    //printf("%u: IfNo: %u\n", recordNo, columnValue);
767
768    spwId = (Int)columnValue ;
769    uInt freqId = freqIdCol.asuInt( recordNo ) ;
770
771    Vector<Float> sp = spectraCol( recordNo ) ;
772    uInt nchan = sp.nelements() ;
773    holder->setNchan( nchan ) ;
774
775    addSpectralWindow( spwId, freqId ) ;
776
777    addFeed( feedId, spwId ) ;
778  }
779  virtual void leaveIfNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
780  }
781  virtual void enterSrcType(const uInt /*recordNo*/, Int columnValue) {
782    //printf("%u: SrcType: %d\n", recordNo, columnValue);
783
784    Int stateId = addState( columnValue ) ;
785
786    // put value
787    *stateIdRF = stateId ;
788  }
789  virtual void leaveSrcType(const uInt /*recordNo*/, Int /*columnValue*/) {
790  }
791  virtual void enterCycleNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
792    //printf("%u: CycleNo: %u\n", recordNo, columnValue);
793  }
794  virtual void leaveCycleNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
795  }
796  virtual void enterTime(const uInt recordNo, Double columnValue) {
797    //printf("%u: Time: %f\n", recordNo, columnValue);
798
799    Double timeSec = columnValue * 86400.0 ;
800    Double interval = intervalCol.asdouble( recordNo ) ;
801
802    if ( ptName.empty() ) {
803      Vector<Double> dir = directionCol( recordNo ) ;
804      Vector<Double> rate = scanRateCol( recordNo ) ;
805      if ( anyNE( rate, 0.0 ) ) {
806        Matrix<Double> msdir( 2, 2 ) ;
807        msdir.column( 0 ) = dir ;
808        msdir.column( 1 ) = rate ;
809        addPointing( timeSec, interval, msdir ) ;
810      }
811      else {
812        Matrix<Double> msdir( 2, 1 ) ;
813        msdir.column( 0 ) = dir ;
814        addPointing( timeSec, interval, msdir ) ;
815      }
816    }
817
818    // put value
819    *timeRF = timeSec ;
820    *timeCentroidRF = timeSec ;
821    *intervalRF = interval ;
822    *exposureRF = interval ;
823  }
824  virtual void leaveTime(const uInt /*recordNo*/, Double /*columnValue*/) {
825    if ( holder->nPol() > 0 ) {
826      Int polId = addPolarization() ;
827      Int ddId = addDataDescription( polId, spwId ) ;
828       
829      // put field
830      *dataDescIdRF = ddId ;
831      holder->post() ;
832     
833      // commit row
834      row.put( rowidx ) ;
835      rowidx++ ;
836
837      // reset holder
838      holder->reset() ;
839    }
840  }
841  virtual void enterPolNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
842    //printf("%u: PolNo: %d\n", recordNo, columnValue);
843  }
844  virtual void leavePolNo(const uInt /*recordNo*/, uInt /*columnValue*/) {
845  }
846
847  virtual Bool visitRecord(const uInt recordNo,
848                           const String &/*fieldName*/,
849                           const uInt /*beamNo*/,
850                           const uInt /*scanNo*/,
851                           const uInt /*ifNo*/,
852                           const Int /*srcType*/,
853                           const uInt /*cycleNo*/,
854                           const Double /*time*/,
855                           const uInt polNo) {
856    //printf("%u: %s, %u, %u, %u, %d, %u, %f, %d\n", recordNo,
857    //       fieldName.c_str(), beamNo, scanNo, ifNo, srcType, cycleNo, time, polNo);
858
859    Vector<Float> sp = spectraCol( recordNo ) ;
860    Vector<uChar> tmp = flagtraCol( recordNo ) ;
861    Vector<Bool> fl( tmp.shape() ) ;
862    convertArray( fl, tmp ) ;
863    Bool flr = (Bool)flagRowCol.asuInt( recordNo ) ;
864    holder->accumulate( polNo, sp, fl, flr ) ;
865
866    return True ;
867  }
868
869  virtual void finish() {
870    BaseMSWriterVisitor::finish();
871    //printf("Total: %u\n", count);
872
873    // remove rows
874    if ( ms.nrow() > rowidx ) {
875      uInt numRemove = ms.nrow() - rowidx ;
876      //cout << "numRemove = " << numRemove << endl ;
877      Vector<uInt> rows( numRemove ) ;
878      indgen( rows, rowidx ) ;
879      ms.removeRow( rows ) ;
880    }
881
882    // fill empty SPECTRAL_WINDOW rows
883    infillSpectralWindow() ;
884
885    // fill empty FIELD rows
886    infillField() ;
887  }
888
889  void dataColumnName( String name )
890  {
891    if ( name == "DATA" )
892      holder = new ComplexDataHolder( row, poltype ) ;
893    else if ( name == "FLOAT_DATA" )
894      holder = new FloatDataHolder( row, poltype ) ;
895  }
896  void pointingTableName( String name ) {
897    ptName = name ;
898  }
899  void setSourceRecord( Record &r ) {
900    srcRec = r ;
901  }
902private:
903  void addField( Int &fid, String &fname, String &srcName,
904                 Vector<Double> &sdir, Vector<Double> &srate,
905                 Double &tSec )
906  {
907    uInt nrow = fieldtab.nrow() ;
908    while( (Int)nrow <= fid ) {
909      fieldtab.addRow( 1, True ) ;
910      nrow++ ;
911    }
912
913    Matrix<Double> dir ;
914    Int numPoly = 0 ;
915    if ( anyNE( srate, 0.0 ) ) {
916      dir.resize( 2, 2 ) ;
917      dir.column( 0 ) = sdir ;
918      dir.column( 1 ) = srate ;
919      numPoly = 1 ;
920    }
921    else {
922      dir.resize( 2, 1 ) ;
923      dir.column( 0 ) = sdir ;
924    }
925    srcId = srcRec.asInt( srcName ) ;
926
927    TableRow tr( fieldtab ) ;
928    TableRecord &r = tr.record() ;
929    putField( "NAME", r, fname ) ;
930    putField( "NUM_POLY", r, numPoly ) ;
931    putField( "TIME", r, tSec ) ;
932    putField( "SOURCE_ID", r, srcId ) ;
933    defineField( "DELAY_DIR", r, dir ) ;
934    defineField( "REFERENCE_DIR", r, dir ) ;
935    defineField( "PHASE_DIR", r, dir ) ;
936    tr.put( fid ) ;
937
938    // for POINTING table
939    *poNameRF = fname ;
940  }
941  Int addState( Int &id )
942  {
943    String obsMode ;
944    Bool isSignal ;
945    Double tnoise ;
946    Double tload ;
947    queryType( id, obsMode, isSignal, tnoise, tload ) ;
948
949    String key = obsMode+"_"+String::toString( subscan ) ;
950    Int idx = -1 ;
951    uInt nEntry = stateEntry.nelements() ;
952    for ( uInt i = 0 ; i < nEntry ; i++ ) {
953      if ( stateEntry[i] == key ) {
954        idx = i ;
955        break ;
956      }
957    }
958    if ( idx == -1 ) {
959      uInt nrow = statetab.nrow() ;
960      statetab.addRow( 1, True ) ;
961      TableRow tr( statetab ) ;
962      TableRecord &r = tr.record() ;
963      putField( "OBS_MODE", r, obsMode ) ;
964      putField( "SIG", r, isSignal ) ;
965      isSignal = !isSignal ;
966      putField( "REF", r, isSignal ) ;
967      putField( "CAL", r, tnoise ) ;
968      putField( "LOAD", r, tload ) ;
969      tr.put( nrow ) ;
970      idx = nrow ;
971
972      stateEntry.resize( nEntry+1, True ) ;
973      stateEntry[nEntry] = key ;
974    }
975    subscan++ ;
976
977    return idx ;
978  }
979  void addPointing( Double &tSec, Double &interval, Matrix<Double> &dir )
980  {
981    uInt nrow = potab.nrow() ;
982    potab.addRow() ;
983
984    *poNumPolyRF = dir.ncolumn() - 1 ;
985    *poTimeRF = tSec ;
986    *poTimeOriginRF = tSec ;
987    *poIntervalRF = interval ;
988    poDirectionRF.define( dir ) ;
989    poTargetRF.define( dir ) ;
990    porow.put( nrow ) ;
991  }
992  Int addPolarization()
993  {
994    Int idx = -1 ;
995    Vector<Int> corrType = holder->corrTypeInt() ;
996    uInt nEntry = polEntry.size() ;
997    for ( uInt i = 0 ; i < nEntry ; i++ ) {
998      if ( polEntry[i].conform( corrType ) && allEQ( polEntry[i], corrType ) ) {
999        idx = i ;
1000        break ;
1001      }
1002    }
1003   
1004    Int numCorr = holder->nPol() ;
1005    Matrix<Int> corrProduct = corrProductTemplate[numCorr].copy() ;
1006    if ( numCorr == 1 && (corrType[0] == Stokes::YY || corrType[0] == Stokes::LL ) ) {
1007      corrProduct = 1;
1008    }
1009
1010    if ( idx == -1 ) {
1011      uInt nrow = poltab.nrow() ;
1012      poltab.addRow( 1, True ) ;
1013      TableRow tr( poltab ) ;
1014      TableRecord &r = tr.record() ;
1015      putField( "NUM_CORR", r, numCorr ) ;
1016      defineField( "CORR_TYPE", r, corrType ) ;
1017      defineField( "CORR_PRODUCT", r, corrProduct ) ;
1018      tr.put( nrow ) ;
1019      idx = nrow ;
1020
1021      polEntry.resize( nEntry+1 ) ;
1022      polEntry[nEntry] = corrType ;
1023    }
1024
1025    return idx ;
1026  }
1027  Int addDataDescription( Int pid, Int sid )
1028  {
1029    Int idx = -1 ;
1030    uInt nItem = 2 ;
1031    uInt len = ddEntry.nelements() ;
1032    uInt nEntry = len / nItem ;
1033    const Int *dd_p = ddEntry.storage() ;
1034    for ( uInt i = 0 ; i < nEntry ; i++ ) {
1035      Int pol = *dd_p ;
1036      dd_p++ ;
1037      Int spw = *dd_p ;
1038      dd_p++ ;
1039      if ( pid == pol && sid == spw ) {
1040        idx = i ;
1041        break ;
1042      }
1043    }
1044
1045    if ( idx == -1 ) {
1046      uInt nrow = ddtab.nrow() ;
1047      ddtab.addRow( 1, True ) ;
1048      TableRow tr( ddtab ) ;
1049      TableRecord &r = tr.record() ;
1050      putField( "POLARIZATION_ID", r, pid ) ;
1051      putField( "SPECTRAL_WINDOW_ID", r, sid ) ;
1052      tr.put( nrow ) ;
1053      idx = nrow ;
1054
1055      ddEntry.resize( len+nItem ) ;
1056      ddEntry[len] = pid ;
1057      ddEntry[len+1] = sid ;
1058    }
1059
1060    return idx ;
1061  }
1062  void infillSpectralWindow()
1063  {
1064    ROScalarColumn<Int> nchanCol( spwtab, "NUM_CHAN" ) ;
1065    Vector<Int> nchan = nchanCol.getColumn() ;
1066    TableRow tr( spwtab ) ;
1067    TableRecord &r = tr.record() ;
1068    Int mfr = freqframe ;
1069    Int oneChan = 1 ;
1070    Vector<Double> dummy( 1, 0.0 ) ;
1071    putField( "MEAS_FREQ_REF", r, mfr ) ;
1072    defineField( "CHAN_FREQ", r, dummy ) ;
1073    defineField( "CHAN_WIDTH", r, dummy ) ;
1074    defineField( "EFFECTIVE_BW", r, dummy ) ;
1075    defineField( "RESOLUTION", r, dummy ) ;
1076    putField( "NUM_CHAN", r, oneChan ) ;
1077
1078    for ( uInt i = 0 ; i < spwtab.nrow() ; i++ ) {
1079      if ( nchan[i] == 0 )
1080        tr.put( i ) ;
1081    }
1082  }
1083  void infillField()
1084  {
1085    ScalarColumn<Int> sourceIdCol(fieldtab, "SOURCE_ID");
1086    ArrayColumn<Double> delayDirCol(fieldtab, "DELAY_DIR");
1087    ArrayColumn<Double> phaseDirCol(fieldtab, "PHASE_DIR");
1088    ArrayColumn<Double> referenceDirCol(fieldtab, "REFERENCE_DIR");
1089    uInt nrow = fieldtab.nrow();
1090    Matrix<Double> dummy(IPosition(2, 2, 1), 0.0);
1091    for (uInt irow = 0; irow < nrow; ++irow) {
1092      if (!phaseDirCol.isDefined(irow)) {
1093        delayDirCol.put(irow, dummy);
1094        phaseDirCol.put(irow, dummy);
1095        referenceDirCol.put(irow, dummy);
1096        sourceIdCol.put(irow, -1);
1097      }
1098    }
1099  }
1100  void addSpectralWindow( Int sid, uInt fid )
1101  {
1102    if (processedFreqId.find((uInt)fid) == processedFreqId.end()
1103        || processedIFNO.find((uInt)sid) == processedIFNO.end() ) {
1104      uInt nrow = spwtab.nrow() ;
1105      while( (Int)nrow <= sid ) {
1106        spwtab.addRow( 1, True ) ;
1107        nrow++ ;
1108      }
1109      processedFreqId.insert((uInt)fid);
1110      processedIFNO.insert((uInt)sid);
1111    }
1112    else {
1113      return ;
1114    }
1115     
1116
1117    Double rp = refpix[fid] ;
1118    Double rv = refval[fid] ;
1119    Double ic = increment[fid] ;
1120
1121    Int mfrInt = (Int)freqframe ;
1122    Int nchan = holder->nChan() ;
1123    Double bw = nchan * abs( ic ) ;
1124    Double reffreq = rv - rp * ic ;
1125    Int netsb = 0 ; // USB->0, LSB->1
1126    if ( ic < 0 )
1127      netsb = 1 ;
1128    Vector<Double> res( nchan, abs(ic) ) ;
1129    Vector<Double> cw( nchan, ic ) ;
1130    Vector<Double> chanf( nchan ) ;
1131    indgen( chanf, reffreq, ic ) ;
1132
1133    TableRow tr( spwtab ) ;
1134    TableRecord &r = tr.record() ;
1135    putField( "MEAS_FREQ_REF", r, mfrInt ) ;
1136    putField( "NUM_CHAN", r, nchan ) ;
1137    putField( "TOTAL_BANDWIDTH", r, bw ) ;
1138    putField( "REF_FREQUENCY", r, reffreq ) ;
1139    putField( "NET_SIDEBAND", r, netsb ) ;
1140    defineField( "RESOLUTION", r, res ) ;
1141//     defineField( "CHAN_WIDTH", r, res ) ;
1142    defineField( "CHAN_WIDTH", r, cw ) ;
1143    defineField( "EFFECTIVE_BW", r, res ) ;
1144    defineField( "CHAN_FREQ", r, chanf ) ;
1145    tr.put( sid ) ;
1146  }
1147  void addFeed( Int fid, Int sid )
1148  {
1149    Int idx = -1 ;
1150    uInt nItem = 2 ;
1151    uInt len = feedEntry.nelements() ;
1152    uInt nEntry = len / nItem ;
1153    const Int *fe_p = feedEntry.storage() ;
1154    for ( uInt i = 0 ; i < nEntry ; i++ ) {
1155      Int feed = *fe_p ;
1156      fe_p++ ;
1157      Int spw = *fe_p ;
1158      fe_p++ ;
1159      if ( fid == feed && sid == spw ) {
1160        idx = i ;
1161        break ;
1162      }
1163    }
1164
1165
1166    if ( idx == -1 ) {
1167      uInt nrow = feedtab.nrow() ;
1168      feedtab.addRow( 1, True ) ;
1169      Int numReceptors = 2 ;
1170      Vector<String> polType( numReceptors ) ;
1171      Matrix<Double> beamOffset( 2, numReceptors, 0.0 ) ;
1172      Vector<Double> receptorAngle( numReceptors, 0.0 ) ;
1173      if ( poltype == "linear" ) {
1174        polType[0] = "X" ;
1175        polType[1] = "Y" ;
1176      }
1177      else if ( poltype == "circular" ) {
1178        polType[0] = "R" ;
1179        polType[1] = "L" ;
1180      }
1181      else {
1182        polType[0] = "X" ;
1183        polType[1] = "Y" ;
1184      }
1185      Matrix<Complex> polResponse( numReceptors, numReceptors, 0.0 ) ;
1186     
1187      TableRow tr( feedtab ) ;
1188      TableRecord &r = tr.record() ;
1189      putField( "FEED_ID", r, fid ) ;
1190      putField( "BEAM_ID", r, fid ) ;
1191      Int tmp = 0 ;
1192      putField( "ANTENNA_ID", r, tmp ) ;
1193      putField( "SPECTRAL_WINDOW_ID", r, sid ) ;
1194      putField( "NUM_RECEPTORS", r, numReceptors ) ;
1195      defineField( "POLARIZATION_TYPE", r, polType ) ;
1196      defineField( "BEAM_OFFSET", r, beamOffset ) ;
1197      defineField( "RECEPTOR_ANGLE", r, receptorAngle ) ;
1198      defineField( "POL_RESPONSE", r, polResponse ) ;
1199      tr.put( nrow ) ;
1200
1201      feedEntry.resize( len+nItem ) ;
1202      feedEntry[len] = fid ;
1203      feedEntry[len+1] = sid ;
1204    }
1205  }
1206  void initPolarization()
1207  {
1208    const TableRecord &keys = table.keywordSet() ;
1209    poltype = keys.asString( "POLTYPE" ) ;
1210
1211    initCorrProductTemplate() ;
1212  }
1213  void initFrequencies()
1214  {
1215    const TableRecord &keys = table.keywordSet() ;
1216    Table tab = keys.asTable( "FREQUENCIES" ) ;
1217    ROScalarColumn<uInt> idcol( tab, "ID" ) ;
1218    ROScalarColumn<Double> rpcol( tab, "REFPIX" ) ;
1219    ROScalarColumn<Double> rvcol( tab, "REFVAL" ) ;
1220    ROScalarColumn<Double> iccol( tab, "INCREMENT" ) ;
1221    Vector<uInt> id = idcol.getColumn() ;
1222    Vector<Double> rp = rpcol.getColumn() ;
1223    Vector<Double> rv = rvcol.getColumn() ;
1224    Vector<Double> ic = iccol.getColumn() ;
1225    for ( uInt i = 0 ; i < id.nelements() ; i++ ) {
1226      refpix.insert( pair<uInt,Double>( id[i], rp[i] ) ) ;
1227      refval.insert( pair<uInt,Double>( id[i], rv[i] ) ) ;
1228      increment.insert( pair<uInt,Double>( id[i], ic[i] ) ) ;
1229    }
1230    String frameStr = tab.keywordSet().asString( "BASEFRAME" ) ;
1231    MFrequency::getType( freqframe, frameStr ) ;
1232  }
1233  void attachSubtables()
1234  {
1235    //const TableRecord &keys = table.keywordSet() ;
1236    TableRecord &mskeys = ms.rwKeywordSet() ;
1237
1238    // FIELD table
1239    fieldtab = mskeys.asTable( "FIELD" ) ;
1240
1241    // SPECTRAL_WINDOW table
1242    spwtab = mskeys.asTable( "SPECTRAL_WINDOW" ) ;
1243
1244    // POINTING table
1245    potab = mskeys.asTable( "POINTING" ) ;
1246
1247    // POLARIZATION table
1248    poltab = mskeys.asTable( "POLARIZATION" ) ;
1249
1250    // DATA_DESCRIPTION table
1251    ddtab = mskeys.asTable( "DATA_DESCRIPTION" ) ;
1252
1253    // STATE table
1254    statetab = mskeys.asTable( "STATE" ) ;
1255
1256    // FEED table
1257    feedtab = mskeys.asTable( "FEED" ) ;
1258  }
1259  void attachMain()
1260  {
1261    TableRecord &r = row.record() ;
1262    dataDescIdRF.attachToRecord( r, "DATA_DESC_ID" ) ;
1263    timeRF.attachToRecord( r, "TIME" ) ;
1264    timeCentroidRF.attachToRecord( r, "TIME_CENTROID" ) ;
1265    intervalRF.attachToRecord( r, "INTERVAL" ) ;
1266    exposureRF.attachToRecord( r, "EXPOSURE" ) ;
1267    fieldIdRF.attachToRecord( r, "FIELD_ID" ) ;
1268    feed1RF.attachToRecord( r, "FEED1" ) ;
1269    feed2RF.attachToRecord( r, "FEED2" ) ;
1270    scanNumberRF.attachToRecord( r, "SCAN_NUMBER" ) ;
1271    stateIdRF.attachToRecord( r, "STATE_ID" ) ;
1272
1273    // constant values
1274    //Int id = 0 ;
1275    RecordFieldPtr<Int> intRF( r, "OBSERVATION_ID" ) ;
1276    *intRF = 0 ;
1277    intRF.attachToRecord( r, "ANTENNA1" ) ;
1278    *intRF = 0 ;
1279    intRF.attachToRecord( r, "ANTENNA2" ) ;
1280    *intRF = 0 ;
1281    intRF.attachToRecord( r, "ARRAY_ID" ) ;
1282    *intRF = 0 ;
1283    intRF.attachToRecord( r, "PROCESSOR_ID" ) ;
1284    *intRF = 0 ;
1285    RecordFieldPtr< Vector<Double> > arrayRF( r, "UVW" ) ;
1286    arrayRF.define( Vector<Double>( 3, 0.0 ) ) ;
1287  }
1288  void attachPointing()
1289  {
1290    porow = TableRow( potab ) ;
1291    TableRecord &r = porow.record() ;
1292    poNumPolyRF.attachToRecord( r, "NUM_POLY" ) ;
1293    poTimeRF.attachToRecord( r, "TIME" ) ;
1294    poTimeOriginRF.attachToRecord( r, "TIME_ORIGIN" ) ;
1295    poIntervalRF.attachToRecord( r, "INTERVAL" ) ;
1296    poNameRF.attachToRecord( r, "NAME" ) ;
1297    poDirectionRF.attachToRecord( r, "DIRECTION" ) ;
1298    poTargetRF.attachToRecord( r, "TARGET" ) ;
1299   
1300    // constant values
1301    RecordFieldPtr<Int> antIdRF( r, "ANTENNA_ID" ) ;
1302    *antIdRF = 0 ;
1303    RecordFieldPtr<Bool> trackingRF( r, "TRACKING" ) ;
1304    *trackingRF = True ;
1305  }
1306  void queryType( Int type, String &stype, Bool &b, Double &t, Double &l )
1307  {
1308    t = 0.0 ;
1309    l = 0.0 ;
1310
1311    String sep1="#" ;
1312    String sep2="," ;
1313    String target="OBSERVE_TARGET" ;
1314    String atmcal="CALIBRATE_TEMPERATURE" ;
1315    String onstr="ON_SOURCE" ;
1316    String offstr="OFF_SOURCE" ;
1317    String pswitch="POSITION_SWITCH" ;
1318    String nod="NOD" ;
1319    String fswitch="FREQUENCY_SWITCH" ;
1320    String sigstr="SIG" ;
1321    String refstr="REF" ;
1322    String unspecified="UNSPECIFIED" ;
1323    String ftlow="LOWER" ;
1324    String fthigh="HIGHER" ;
1325    switch ( type ) {
1326    case SrcType::PSON:
1327      stype = target+sep1+onstr+sep2+pswitch ;
1328      b = True ;
1329      break ;
1330    case SrcType::PSOFF:
1331      stype = target+sep1+offstr+sep2+pswitch ;
1332      b = False ;
1333      break ;
1334    case SrcType::NOD:
1335      stype = target+sep1+onstr+sep2+nod ;
1336      b = True ;
1337      break ;
1338    case SrcType::FSON:
1339      stype = target+sep1+onstr+sep2+fswitch+sep1+sigstr ;
1340      b = True ;
1341      break ;
1342    case SrcType::FSOFF:
1343      stype = target+sep1+onstr+sep2+fswitch+sep1+refstr ;
1344      b = False ;
1345      break ;
1346    case SrcType::SKY:
1347      stype = atmcal+sep1+offstr+sep2+unspecified ;
1348      b = False ;
1349      break ;
1350    case SrcType::HOT:
1351      stype = atmcal+sep1+offstr+sep2+unspecified ;
1352      b = False ;
1353      break ;
1354    case SrcType::WARM:
1355      stype = atmcal+sep1+offstr+sep2+unspecified ;
1356      b = False ;
1357      break ;
1358    case SrcType::COLD:
1359      stype = atmcal+sep1+offstr+sep2+unspecified ;
1360      b = False ;
1361      break ;
1362    case SrcType::PONCAL:
1363      stype = atmcal+sep1+onstr+sep2+pswitch ;
1364      b = True ;
1365      break ;
1366    case SrcType::POFFCAL:
1367      stype = atmcal+sep1+offstr+sep2+pswitch ;
1368      b = False ;
1369      break ;
1370    case SrcType::NODCAL:
1371      stype = atmcal+sep1+onstr+sep2+nod ;
1372      b = True ;
1373      break ;
1374    case SrcType::FONCAL:
1375      stype = atmcal+sep1+onstr+sep2+fswitch+sep1+sigstr ;
1376      b = True ;
1377      break ;
1378    case SrcType::FOFFCAL:
1379      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+refstr ;
1380      b = False ;
1381      break ;
1382    case SrcType::FSLO:
1383      stype = target+sep1+onstr+sep2+fswitch+sep1+ftlow ;
1384      b = True ;
1385      break ;
1386    case SrcType::FLOOFF:
1387      stype = target+sep1+offstr+sep2+fswitch+sep1+ftlow ;
1388      b = False ;
1389      break ;
1390    case SrcType::FLOSKY:
1391      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+ftlow ;
1392      b = False ;
1393      break ;
1394    case SrcType::FLOHOT:
1395      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+ftlow ;
1396      b = False ;
1397      break ;
1398    case SrcType::FLOWARM:
1399      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+ftlow ;
1400      b = False ;
1401      break ;
1402    case SrcType::FLOCOLD:
1403      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+ftlow ;
1404      b = False ;
1405      break ;
1406    case SrcType::FSHI:
1407      stype = target+sep1+onstr+sep2+fswitch+sep1+fthigh ;
1408      b = True ;
1409      break ;
1410    case SrcType::FHIOFF:
1411      stype = target+sep1+offstr+sep2+fswitch+sep1+fthigh ;
1412      b = False ;
1413      break ;
1414    case SrcType::FHISKY:
1415      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+fthigh ;
1416      b = False ;
1417      break ;
1418    case SrcType::FHIHOT:
1419      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+fthigh ;
1420      b = False ;
1421      break ;
1422    case SrcType::FHIWARM:
1423      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+fthigh ;
1424      b = False ;
1425      break ;
1426    case SrcType::FHICOLD:
1427      stype = atmcal+sep1+offstr+sep2+fswitch+sep1+fthigh ;
1428      b = False ;
1429      break ;
1430    case SrcType::SIG:
1431      stype = target+sep1+onstr+sep2+unspecified ;
1432      b = True ;
1433      break ;
1434    case SrcType::REF:
1435      stype = target+sep1+offstr+sep2+unspecified ;
1436      b = False ;
1437      break ;
1438    default:
1439      stype = unspecified ;
1440      b = True ;
1441      break ;
1442    }
1443  }
1444  void initCorrProductTemplate()
1445  {
1446    Int n = 1 ;
1447    {
1448      Matrix<Int> c( 2, n, 0 ) ;
1449      corrProductTemplate[n] = c ;
1450    }
1451    n = 2 ;
1452    {
1453      Matrix<Int> c( 2, n, 0 ) ;
1454      c.column( 1 ) = 1 ;
1455      corrProductTemplate[n] = c ;
1456    }
1457    n = 4 ;
1458    {
1459      Matrix<Int> c( 2, n, 0 ) ;
1460      c( 0, 2 ) = 1 ;
1461      c( 0, 3 ) = 1 ;
1462      c( 1, 1 ) = 1 ;
1463      c( 1, 3 ) = 1 ;
1464      corrProductTemplate[n] = c ;
1465    }
1466  }
1467
1468  Table &ms;
1469  TableRow row;
1470  uInt rowidx;
1471  String fieldName;
1472  Int fieldId;
1473  Int srcId;
1474  Int defaultFieldId;
1475  Int spwId;
1476  Int feedId;
1477  Int subscan;
1478  CountedPtr<DataHolder> holder;
1479  String ptName;
1480  Bool useFloat;
1481  String poltype;
1482
1483  // MS subtables
1484  Table spwtab;
1485  Table statetab;
1486  Table ddtab;
1487  Table poltab;
1488  Table fieldtab;
1489  Table feedtab;
1490  Table potab;
1491
1492  // Scantable MAIN columns
1493  ROArrayColumn<Float> spectraCol;
1494  ROArrayColumn<Double> directionCol,scanRateCol,sourceDirectionCol;
1495  ROArrayColumn<uChar> flagtraCol;
1496  ROTableColumn tcalIdCol,intervalCol,flagRowCol,timeCol,freqIdCol,
1497    sourceNameCol,fieldNameCol;
1498
1499  // MS MAIN columns
1500  RecordFieldPtr<Int> dataDescIdRF,fieldIdRF,feed1RF,feed2RF,
1501    scanNumberRF,stateIdRF;
1502  RecordFieldPtr<Double> timeRF,timeCentroidRF,intervalRF,exposureRF;
1503
1504  // MS POINTING columns
1505  TableRow porow;
1506  RecordFieldPtr<Int> poNumPolyRF ;
1507  RecordFieldPtr<Double> poTimeRF,
1508    poTimeOriginRF,
1509    poIntervalRF ;
1510  RecordFieldPtr<String> poNameRF ;
1511  RecordFieldPtr< Matrix<Double> > poDirectionRF,
1512    poTargetRF ;
1513
1514  Vector<String> stateEntry;
1515  Block<Int> ddEntry;
1516  Block<Int> feedEntry;
1517  vector< Vector<Int> > polEntry;
1518  set<uInt> processedFreqId;
1519  set<uInt> processedIFNO;
1520  map<uInt,Double> refpix;
1521  map<uInt,Double> refval;
1522  map<uInt,Double> increment;
1523  MFrequency::Types freqframe;
1524  Record srcRec;
1525  map< Int, Matrix<Int> > corrProductTemplate;
1526};
1527
1528class BaseMSSysCalVisitor: public TableVisitor {
1529  uInt lastRecordNo;
1530  uInt lastBeamNo, lastIfNo, lastPolNo;
1531  Double lastTime;
1532protected:
1533  const Table &table;
1534  uInt count;
1535public:
1536  BaseMSSysCalVisitor(const Table &table)
1537    : table(table)
1538  {
1539    count = 0;
1540  }
1541 
1542  virtual void enterBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1543  virtual void leaveBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1544  virtual void enterIfNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1545  virtual void leaveIfNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1546  virtual void enterPolNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1547  virtual void leavePolNo(const uInt /*recordNo*/, uInt /*columnValue*/) { }
1548  virtual void enterTime(const uInt /*recordNo*/, Double /*columnValue*/) { }
1549  virtual void leaveTime(const uInt /*recordNo*/, Double /*columnValue*/) { }
1550
1551  virtual Bool visitRecord(const uInt /*recordNo*/,
1552                           const uInt /*beamNo*/,
1553                           const uInt /*ifNo*/,
1554                           const uInt /*polNo*/,
1555                           const Double /*time*/) { return True ;}
1556
1557  virtual Bool visit(Bool isFirst, const uInt recordNo,
1558                     const uInt nCols, void const *const colValues[]) {
1559    uInt beamNo, ifNo, polNo;
1560    Double time;
1561    { // prologue
1562      uInt i = 0;
1563      {
1564        const uInt *col = (const uInt *)colValues[i++];
1565        beamNo = col[recordNo];
1566      }
1567      {
1568        const uInt *col = (const uInt *)colValues[i++];
1569        ifNo = col[recordNo];
1570      }
1571      {
1572        const Double *col = (const Double *)colValues[i++];
1573        time = col[recordNo];
1574      }
1575      {
1576        const uInt *col = (const uInt *)colValues[i++];
1577        polNo = col[recordNo];
1578      }
1579      assert(nCols == i);
1580    }
1581
1582    if (isFirst) {
1583      enterBeamNo(recordNo, beamNo);
1584      enterIfNo(recordNo, ifNo);
1585      enterTime(recordNo, time);
1586      enterPolNo(recordNo, polNo);
1587    } else {
1588      if (lastBeamNo != beamNo) {
1589        leavePolNo(lastRecordNo, lastPolNo);
1590        leaveTime(lastRecordNo, lastTime);
1591        leaveIfNo(lastRecordNo, lastIfNo);
1592        leaveBeamNo(lastRecordNo, lastBeamNo);
1593
1594        enterBeamNo(recordNo, beamNo);
1595        enterIfNo(recordNo, ifNo);
1596        enterTime(recordNo, time);
1597        enterPolNo(recordNo, polNo);
1598      } else if (lastIfNo != ifNo) {
1599        leavePolNo(lastRecordNo, lastPolNo);
1600        leaveTime(lastRecordNo, lastTime);
1601        leaveIfNo(lastRecordNo, lastIfNo);
1602       
1603        enterIfNo(recordNo, ifNo);
1604        enterTime(recordNo, time);
1605        enterPolNo(recordNo, polNo);
1606      } else if (lastTime != time) {
1607        leavePolNo(lastRecordNo, lastPolNo);
1608        leaveTime(lastRecordNo, lastTime);
1609
1610        enterTime(recordNo, time);
1611        enterPolNo(recordNo, polNo);
1612      } else if (lastPolNo != polNo) {
1613        leavePolNo(lastRecordNo, lastPolNo);
1614        enterPolNo(recordNo, polNo);
1615      }
1616    }
1617    count++;
1618    Bool result = visitRecord(recordNo, beamNo, ifNo, polNo, time);
1619
1620    { // epilogue
1621      lastRecordNo = recordNo;
1622
1623      lastBeamNo = beamNo;
1624      lastIfNo = ifNo;
1625      lastPolNo = polNo;
1626      lastTime = time;
1627    }
1628    return result ;
1629  }
1630
1631  virtual void finish() {
1632    if (count > 0) {
1633      leavePolNo(lastRecordNo, lastPolNo);
1634      leaveTime(lastRecordNo, lastTime);
1635      leaveIfNo(lastRecordNo, lastIfNo);
1636      leaveBeamNo(lastRecordNo, lastBeamNo);
1637    }
1638  }
1639};
1640
1641class BaseTsysHolder
1642{
1643public:
1644  BaseTsysHolder( ROArrayColumn<Float> &tsysCol )
1645    : col( tsysCol ),
1646      nchan(0)
1647  {
1648    reset() ;
1649  }
1650  virtual ~BaseTsysHolder() {}
1651  virtual Array<Float> getTsys() = 0 ;
1652  void setNchan( uInt n ) { nchan = n ; }
1653  void appendTsys( uInt row )
1654  {
1655    Vector<Float> v = col( row ) ;
1656    uInt len = tsys.nrow() ;
1657    tsys.resize( len+1, nchan, True ) ;
1658    if ( v.nelements() == nchan )
1659      tsys.row( len ) = v ;
1660    else
1661      tsys.row( len ) = v[0] ;
1662  }
1663  void setTsys( uInt row, uInt idx )
1664  {
1665    if ( idx >= nrow() )
1666      appendTsys( row ) ;
1667    else {
1668      Vector<Float> v = col( row ) ;
1669      if ( v.nelements() == nchan )
1670        tsys.row( idx ) = v ;
1671      else
1672        tsys.row( idx ) = v[0] ;
1673    }
1674  }
1675  void reset()
1676  {
1677    tsys.resize() ;
1678  }
1679  uInt nrow() { return tsys.nrow() ; }
1680  Bool isEffective()
1681  {
1682    return ( !(tsys.empty()) && anyNE( tsys, (Float)1.0 ) ) ;
1683  }
1684  BaseTsysHolder &operator= ( const BaseTsysHolder &v )
1685  {
1686    if ( this != &v )
1687      tsys.assign( v.tsys ) ;
1688    return *this ;
1689  }
1690protected:
1691  ROArrayColumn<Float> col ;
1692  Matrix<Float> tsys ;
1693  uInt nchan ;
1694};
1695
1696class TsysHolder : public BaseTsysHolder
1697{
1698public:
1699  TsysHolder( ROArrayColumn<Float> &tsysCol )
1700    : BaseTsysHolder( tsysCol )
1701  {}
1702  virtual ~TsysHolder() {}
1703  virtual Array<Float> getTsys()
1704  {
1705    return tsys.column( 0 ) ;
1706  }
1707};
1708
1709class TsysSpectrumHolder : public BaseTsysHolder
1710{
1711public:
1712  TsysSpectrumHolder( ROArrayColumn<Float> &tsysCol )
1713    : BaseTsysHolder( tsysCol )
1714  {}
1715  virtual ~TsysSpectrumHolder() {}
1716  virtual Array<Float> getTsys()
1717  {
1718    return tsys ;
1719  }
1720};
1721
1722class BaseTcalProcessor
1723{
1724public:
1725  BaseTcalProcessor( ROArrayColumn<Float> &tcalCol )
1726    : col_( tcalCol )
1727  {}
1728  virtual ~BaseTcalProcessor() {}
1729  void setTcalId( Vector<uInt> &tcalId ) { id_.assign( tcalId ) ; }
1730  virtual Array<Float> getTcal() = 0 ;
1731protected:
1732  ROArrayColumn<Float> col_ ;
1733  Vector<uInt> id_ ;
1734};
1735
1736class TcalProcessor : public BaseTcalProcessor
1737{
1738public:
1739  TcalProcessor( ROArrayColumn<Float> &tcalCol )
1740    : BaseTcalProcessor( tcalCol )
1741  {}
1742  virtual ~TcalProcessor() {}
1743  virtual Array<Float> getTcal()
1744  {
1745    uInt npol = id_.nelements() ;
1746    Vector<Float> tcal( npol ) ;
1747    for ( uInt ipol = 0 ; ipol < npol ; ipol++ )
1748      tcal[ipol] = col_( id_[ipol] ).data()[0] ;
1749    //cout << "TcalProcessor: tcal = " << tcal << endl ;
1750    return tcal ;
1751  }
1752};
1753
1754class TcalSpectrumProcessor : public BaseTcalProcessor
1755{
1756public:
1757  TcalSpectrumProcessor( ROArrayColumn<Float> &tcalCol )
1758    : BaseTcalProcessor( tcalCol )
1759  {}
1760  virtual ~TcalSpectrumProcessor() {}
1761  virtual Array<Float> getTcal()
1762  {
1763    uInt npol = id_.nelements() ;
1764    //Vector<Float> tcal0 = col_( 0 ) ;
1765    Vector<Float> tcal0 = col_( id_[0] ) ;
1766    uInt nchan = tcal0.nelements() ;
1767    Matrix<Float> tcal( npol, nchan ) ;
1768    tcal.row( 0 ) = tcal0 ;
1769    for ( uInt ipol = 1 ; ipol < npol ; ipol++ )
1770      tcal.row( ipol ) = col_( id_[ipol] ) ;
1771    return tcal ;
1772  }
1773};
1774
1775class MSSysCalVisitor : public BaseMSSysCalVisitor
1776{
1777public:
1778  MSSysCalVisitor( const Table &from, Table &to )
1779    : BaseMSSysCalVisitor( from ),
1780      sctab( to ),
1781      rowidx( 0 ),
1782      polno_()
1783  {
1784    scrow = TableRow( sctab ) ;
1785
1786    lastTcalId.resize() ;
1787    theTcalId.resize() ;
1788    startTime = 0.0 ;
1789    endTime = 0.0 ;
1790
1791    const TableRecord &keys = table.keywordSet() ;
1792    Table tcalTable = keys.asTable( "TCAL" ) ;
1793    tcalCol.attach( tcalTable, "TCAL" ) ;
1794    tsysCol.attach( table, "TSYS" ) ;
1795    tcalIdCol.attach( table, "TCAL_ID" ) ;
1796    intervalCol.attach( table, "INTERVAL" ) ;
1797    effectiveTcal.resize( tcalTable.nrow() ) ;
1798    for ( uInt irow = 0 ; irow < tcalTable.nrow() ; irow++ ) {
1799      if ( allEQ( tcalCol( irow ), (Float)1.0 ) )
1800        effectiveTcal[irow] = False ;
1801      else
1802        effectiveTcal[irow] = True ;
1803    }
1804   
1805    TableRecord &r = scrow.record() ;
1806    RecordFieldPtr<Int> antennaIdRF( r, "ANTENNA_ID" ) ;
1807    *antennaIdRF = 0 ;
1808    feedIdRF.attachToRecord( r, "FEED_ID" ) ;
1809    specWinIdRF.attachToRecord( r, "SPECTRAL_WINDOW_ID" ) ;
1810    timeRF.attachToRecord( r, "TIME" ) ;
1811    intervalRF.attachToRecord( r, "INTERVAL" ) ;
1812    if ( r.isDefined( "TCAL" ) ) {
1813      tcalRF.attachToRecord( r, "TCAL" ) ;
1814      tcalProcessor = new TcalProcessor( tcalCol ) ;
1815    }
1816    else if ( r.isDefined( "TCAL_SPECTRUM" ) ) {
1817      tcalRF.attachToRecord( r, "TCAL_SPECTRUM" ) ;
1818      tcalProcessor = new TcalSpectrumProcessor( tcalCol ) ;
1819    }
1820    if ( r.isDefined( "TSYS" ) ) {
1821      tsysRF.attachToRecord( r, "TSYS" ) ;
1822      theTsys = new TsysHolder( tsysCol ) ;
1823      lastTsys = new TsysHolder( tsysCol ) ;
1824    }
1825    else {
1826      tsysRF.attachToRecord( r, "TSYS_SPECTRUM" ) ;
1827      theTsys = new TsysSpectrumHolder( tsysCol ) ;
1828      lastTsys = new TsysSpectrumHolder( tsysCol ) ;
1829    }
1830
1831  }
1832
1833  virtual void enterBeamNo(const uInt /*recordNo*/, uInt columnValue)
1834  {
1835    *feedIdRF = (Int)columnValue ;
1836  }
1837  virtual void leaveBeamNo(const uInt /*recordNo*/, uInt /*columnValue*/)
1838  {
1839  }
1840  virtual void enterIfNo(const uInt recordNo, uInt columnValue)
1841  {
1842    //cout << "enterIfNo" << endl ;
1843    ROArrayColumn<Float> sp( table, "SPECTRA" ) ;
1844    uInt nchan = sp( recordNo ).nelements() ;
1845    theTsys->setNchan( nchan ) ;
1846    lastTsys->setNchan( nchan ) ;
1847
1848    *specWinIdRF = (Int)columnValue ;
1849  }
1850  virtual void leaveIfNo(const uInt /*recordNo*/, uInt /*columnValue*/)
1851  {
1852    //cout << "leaveIfNo" << endl ;
1853    post() ;
1854    reset(true);
1855    startTime = 0.0 ;
1856    endTime = 0.0 ;
1857  }
1858  virtual void enterTime(const uInt recordNo, Double columnValue)
1859  {
1860    //cout << "enterTime" << endl ;
1861    interval = intervalCol.asdouble( recordNo ) ;
1862    // start time and end time
1863    if ( startTime == 0.0 ) {
1864      startTime = columnValue * 86400.0 - 0.5 * interval ;
1865      endTime = columnValue * 86400.0 + 0.5 * interval ;
1866    }
1867  }
1868  virtual void leaveTime(const uInt /*recordNo*/, Double columnValue)
1869  {
1870    //cout << "leaveTime" << endl ;
1871    if ( isUpdated() ) {
1872      post() ;
1873      *lastTsys = *theTsys ;
1874      lastTcalId = theTcalId ;
1875      reset(false);
1876      startTime = columnValue * 86400.0 - 0.5 * interval ;
1877      endTime = columnValue * 86400.0 + 0.5 * interval ;
1878    }
1879    else {
1880      endTime = columnValue * 86400.0 + 0.5 * interval ;
1881    }
1882  }
1883  virtual void enterPolNo(const uInt recordNo, uInt columnValue)
1884  {
1885    //cout << "enterPolNo" << endl ;
1886    Vector<Float> tsys = tsysCol( recordNo ) ;
1887    uInt tcalId = tcalIdCol.asuInt( recordNo ) ;
1888    polno_.insert( columnValue ) ;
1889    uInt numPol = polno_.size() ;
1890    if ( lastTsys->nrow() < numPol )
1891      lastTsys->appendTsys( recordNo ) ;
1892    if ( lastTcalId.nelements() <= numPol )
1893      appendTcalId( lastTcalId, tcalId, numPol-1 ) ;
1894    if ( theTsys->nrow() < numPol )
1895      theTsys->appendTsys( recordNo ) ;
1896    else {
1897      theTsys->setTsys( recordNo, numPol-1 ) ;
1898    }
1899    if ( theTcalId.nelements() < numPol )
1900      appendTcalId( theTcalId, tcalId, numPol-1 ) ;
1901    else
1902      setTcalId( theTcalId, tcalId, numPol-1 ) ;
1903  }
1904  virtual void leavePolNo( const uInt /*recordNo*/, uInt /*columnValue*/ )
1905  {
1906  }
1907   
1908private:
1909  void reset(bool completely)
1910  {
1911    if (completely) {
1912      lastTsys->reset() ;
1913      lastTcalId.resize() ;
1914    }
1915    theTsys->reset() ;
1916    theTcalId.resize() ;
1917    polno_.clear();
1918  }
1919  void appendTcalId( Vector<uInt> &v, uInt &elem, uInt polId )
1920  {
1921    v.resize( polId+1, True ) ;
1922    v[polId] = elem ;
1923  }
1924  void setTcalId( Vector<uInt> &v, uInt &elem, uInt polId )
1925  {
1926    v[polId] = elem ;
1927  }
1928  void post()
1929  {
1930    // check if given Tcal and Tsys is effective
1931    Bool isEffective = False ;
1932    for ( uInt ipol = 0 ; ipol < lastTcalId.nelements() ; ipol++ ) {
1933      if ( effectiveTcal[lastTcalId[ipol]] ) {
1934        isEffective = True ;
1935        break ;
1936      }
1937    }
1938    if ( !isEffective ) {
1939      if ( !(lastTsys->isEffective()) )
1940        return ;
1941    }
1942
1943    //cout << " interval: " << (endTime-startTime) << " lastTcalId = " << lastTcalId << endl ;
1944    Double midTime = 0.5 * ( startTime + endTime ) ;
1945    Double interval = endTime - startTime ;
1946    *timeRF = midTime ;
1947    *intervalRF = interval ;
1948    tcalProcessor->setTcalId( lastTcalId ) ;
1949    Array<Float> tcal = tcalProcessor->getTcal() ;
1950    Array<Float> tsys = lastTsys->getTsys() ;
1951    tcalRF.define( tcal ) ;
1952    tsysRF.define( tsys ) ;
1953    sctab.addRow( 1, True ) ;
1954    scrow.put( rowidx ) ;
1955    rowidx++ ;
1956  }
1957 
1958  Bool isUpdated()
1959  {
1960    Bool ret = (anyNE( theTcalId, lastTcalId ) || anyNE( theTsys->getTsys(), lastTsys->getTsys() )) ;
1961    return ret ;
1962  }
1963
1964  Table &sctab;
1965  TableRow scrow;
1966  uInt rowidx;
1967
1968  Double startTime,endTime,interval;
1969 
1970  CountedPtr<BaseTsysHolder> lastTsys,theTsys;
1971  Vector<uInt> lastTcalId,theTcalId;
1972  set<uInt> polno_;
1973  CountedPtr<BaseTcalProcessor> tcalProcessor ;
1974  Vector<Bool> effectiveTcal;
1975
1976  RecordFieldPtr<Int> feedIdRF,specWinIdRF;
1977  RecordFieldPtr<Double> timeRF,intervalRF;
1978  RecordFieldPtr< Array<Float> > tcalRF,tsysRF;
1979
1980  ROArrayColumn<Float> tsysCol,tcalCol;
1981  ROTableColumn tcalIdCol,intervalCol;
1982};
1983
1984MSWriter::MSWriter(CountedPtr<Scantable> stable)
1985  : table_(stable),
1986    mstable_(NULL),
1987    isWeather_(False),
1988    tcalSpec_(False),
1989    tsysSpec_(False),
1990    ptTabName_("")
1991{
1992  os_ = LogIO() ;
1993  os_.origin( LogOrigin( "MSWriter", "MSWriter()", WHERE ) ) ;
1994//   os_ << "MSWriter::MSWriter()" << LogIO::POST ;
1995
1996  // initialize writer
1997  init() ;
1998}
1999
2000MSWriter::~MSWriter()
2001{
2002  os_.origin( LogOrigin( "MSWriter", "~MSWriter()", WHERE ) ) ;
2003//   os_ << "MSWriter::~MSWriter()" << LogIO::POST ;
2004
2005  if ( mstable_ != 0 )
2006    delete mstable_ ;
2007}
2008
2009bool MSWriter::write(const string& filename, const Record& rec)
2010{
2011  os_.origin( LogOrigin( "MSWriter", "write()", WHERE ) ) ;
2012  //double startSec = mathutil::gettimeofday_sec() ;
2013  //os_ << "start MSWriter::write() startSec=" << startSec << LogIO::POST ;
2014
2015  filename_ = filename ;
2016
2017  // parsing MS options
2018  Bool overwrite = False ;
2019  if ( rec.isDefined( "ms" ) ) {
2020    Record msrec = rec.asRecord( "ms" ) ;
2021    if ( msrec.isDefined( "overwrite" ) ) {
2022      overwrite = msrec.asBool( "overwrite" ) ;
2023    }
2024  }
2025
2026  os_ << "Parsing MS options" << endl ;
2027  os_ << "   overwrite = " << overwrite << LogIO::POST ;
2028
2029  File file( filename_ ) ;
2030  if ( file.exists() ) {
2031    if ( overwrite ) {
2032      os_ << filename_ << " exists. Overwrite existing data... " << LogIO::POST ;
2033      if ( file.isRegular() ) RegularFile(file).remove() ;
2034      else if ( file.isDirectory() ) Directory(file).removeRecursive() ;
2035      else SymLink(file).remove() ;
2036    }
2037    else {
2038      os_ << LogIO::SEVERE << "ERROR: " << filename_ << " exists..." << LogIO::POST ;
2039      return False ;
2040    }
2041  }
2042
2043  // set up MS
2044  setupMS() ;
2045 
2046  // subtables
2047  // OBSERVATION
2048  fillObservation() ;
2049
2050  // ANTENNA
2051  fillAntenna() ;
2052
2053  // PROCESSOR
2054  fillProcessor() ;
2055
2056  // SOURCE
2057  fillSource() ;
2058
2059  // WEATHER
2060  if ( isWeather_ )
2061    fillWeather() ;
2062
2063  // SYSCAL
2064  fillSysCal() ;
2065
2066  /***
2067   * Start iteration using TableVisitor
2068   ***/
2069  {
2070    static const char *cols[] = {
2071      "FIELDNAME", "BEAMNO", "SCANNO", "IFNO", "SRCTYPE", "CYCLENO", "TIME",
2072      "POLNO",
2073      NULL
2074    };
2075    static const TypeManagerImpl<uInt> tmUInt;
2076    static const TypeManagerImpl<Int> tmInt;
2077    static const TypeManagerImpl<Double> tmDouble;
2078    static const TypeManagerImpl<String> tmString;
2079    static const TypeManager *const tms[] = {
2080      &tmString, &tmUInt, &tmUInt, &tmUInt, &tmInt, &tmUInt, &tmDouble, &tmUInt, NULL
2081    };
2082    //double t0 = mathutil::gettimeofday_sec() ;
2083    MSWriterVisitor myVisitor(table_->table(),*mstable_);
2084    //double t1 = mathutil::gettimeofday_sec() ;
2085    //cout << "MSWriterVisitor(): elapsed time " << t1-t0 << " sec" << endl ;
2086    String dataColName = "FLOAT_DATA" ;
2087    if ( useData_ )
2088      dataColName = "DATA" ;
2089    myVisitor.dataColumnName( dataColName ) ;
2090    myVisitor.pointingTableName( ptTabName_ ) ;
2091    myVisitor.setSourceRecord( srcRec_ ) ;
2092    //double t2 = mathutil::gettimeofday_sec() ;
2093    traverseTable(table_->table(), cols, tms, &myVisitor);
2094    //double t3 = mathutil::gettimeofday_sec() ;
2095    //cout << "traverseTable(): elapsed time " << t3-t2 << " sec" << endl ;
2096  }
2097  /***
2098   * End iteration using TableVisitor
2099   ***/
2100
2101  // ASDM tables
2102  const TableRecord &stKeys = table_->table().keywordSet() ;
2103  TableRecord &msKeys = mstable_->rwKeywordSet() ;
2104  uInt nfields = stKeys.nfields() ;
2105  for ( uInt ifield = 0 ; ifield < nfields ; ifield++ ) {
2106    String kname = stKeys.name( ifield ) ;
2107    if ( kname.find( "ASDM" ) != String::npos ) {
2108      String asdmpath = stKeys.asString( ifield ) ;
2109      os_ << "found ASDM table: " << asdmpath << LogIO::POST ;
2110      if ( Table::isReadable( asdmpath ) ) {
2111        Table newAsdmTab( asdmpath, Table::Old ) ;
2112        newAsdmTab.copy( filename_+"/"+kname, Table::New ) ;
2113        os_ << "add subtable: " << kname << LogIO::POST ;
2114        msKeys.defineTable( kname, Table( filename_+"/"+kname, Table::Old ) ) ;
2115      }
2116    }
2117  }
2118
2119  // replace POINTING table with original one if exists
2120  if ( ptTabName_ != "" ) {
2121    delete mstable_ ;
2122    mstable_ = 0 ;
2123    Table newPtTab( ptTabName_, Table::Old ) ;
2124    newPtTab.copy( filename_+"/POINTING", Table::New ) ;
2125  }
2126
2127  //double endSec = mathutil::gettimeofday_sec() ;
2128  //os_ << "end MSWriter::write() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2129
2130  os_ << "Exported data as MS" << LogIO::POST ;
2131
2132  return True ;
2133}
2134
2135void MSWriter::init()
2136{
2137//   os_.origin( LogOrigin( "MSWriter", "init()", WHERE ) ) ;
2138//   double startSec = mathutil::gettimeofday_sec() ;
2139//   os_ << "start MSWriter::init() startSec=" << startSec << LogIO::POST ;
2140 
2141  // access to scantable
2142  header_ = table_->getHeader() ;
2143
2144  // FLOAT_DATA? or DATA?
2145  if ( header_.npol > 2 ) {
2146    useFloatData_ = False ;
2147    useData_ = True ;
2148  }
2149  else {
2150    useFloatData_ = True ;
2151    useData_ = False ;
2152  }
2153
2154  // polarization type
2155  polType_ = header_.poltype ;
2156  if ( polType_ == "" )
2157    polType_ = "stokes" ;
2158  else if ( polType_.find( "linear" ) != String::npos )
2159    polType_ = "linear" ;
2160  else if ( polType_.find( "circular" ) != String::npos )
2161    polType_ = "circular" ;
2162  else if ( polType_.find( "stokes" ) != String::npos )
2163    polType_ = "stokes" ;
2164  else if ( polType_.find( "linpol" ) != String::npos )
2165    polType_ = "linpol" ;
2166  else
2167    polType_ = "notype" ;
2168
2169  // Check if some subtables are exists
2170  Bool isTcal = False ;
2171  if ( table_->tcal().table().nrow() != 0 ) {
2172    ROTableColumn col( table_->tcal().table(), "TCAL" ) ;
2173    if ( col.isDefined( 0 ) ) {
2174      os_ << "TCAL table exists: nrow=" << table_->tcal().table().nrow() << LogIO::POST ;
2175      isTcal = True ;
2176    }
2177    else {
2178      os_ << "No TCAL rows" << LogIO::POST ;
2179    }
2180  }
2181  else {
2182    os_ << "No TCAL rows" << LogIO::POST ;
2183  }
2184  if ( table_->weather().table().nrow() != 0 ) {
2185    ROTableColumn col( table_->weather().table(), "TEMPERATURE" ) ;
2186    if ( col.isDefined( 0 ) ) {
2187      os_ << "WEATHER table exists: nrow=" << table_->weather().table().nrow() << LogIO::POST ;
2188      isWeather_ =True ;
2189    }
2190    else {
2191      os_ << "No WEATHER rows" << LogIO::POST ;
2192    }
2193  }
2194  else {
2195    os_ << "No WEATHER rows" << LogIO::POST ;
2196  }
2197
2198  // Are TCAL_SPECTRUM and TSYS_SPECTRUM necessary?
2199  if ( header_.nchan != 1 ) {
2200    if ( isTcal ) {
2201      // examine TCAL subtable
2202      Table tcaltab = table_->tcal().table() ;
2203      ROArrayColumn<Float> tcalCol( tcaltab, "TCAL" ) ;
2204      for ( uInt irow = 0 ; irow < tcaltab.nrow() ; irow++ ) {
2205        if ( tcalCol( irow ).size() != 1 )
2206          tcalSpec_ = True ;
2207      }
2208    }
2209    // examine spectral data
2210    TableIterator iter0( table_->table(), "IFNO" ) ;
2211    while( !iter0.pastEnd() ) {
2212      Table t0( iter0.table() ) ;
2213      ROArrayColumn<Float> sharedFloatArrCol( t0, "SPECTRA" ) ;
2214      uInt len = sharedFloatArrCol( 0 ).size() ;
2215      if ( len != 1 ) {
2216        sharedFloatArrCol.attach( t0, "TSYS" ) ;
2217        if ( sharedFloatArrCol( 0 ).size() != 1 )
2218          tsysSpec_ = True ;
2219      }
2220      iter0.next() ;
2221    }
2222  }
2223
2224  // check if reference for POINTING table exists
2225  const TableRecord &rec = table_->table().keywordSet() ;
2226  if ( rec.isDefined( "POINTING" ) ) {
2227    ptTabName_ = rec.asString( "POINTING" ) ;
2228    if ( !Table::isReadable( ptTabName_ ) ) {
2229      ptTabName_ = "" ;
2230    }
2231  }
2232
2233//   double endSec = mathutil::gettimeofday_sec() ;
2234//   os_ << "end MSWriter::init() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2235}
2236
2237void MSWriter::setupMS()
2238{
2239//   os_.origin( LogOrigin( "MSWriter", "setupMS()", WHERE ) ) ;
2240//   double startSec = mathutil::gettimeofday_sec() ;
2241//   os_ << "start MSWriter::setupMS() startSec=" << startSec << LogIO::POST ;
2242 
2243  String dunit = table_->getHeader().fluxunit ;
2244
2245  TableDesc msDesc = MeasurementSet::requiredTableDesc() ;
2246  if ( useFloatData_ )
2247    MeasurementSet::addColumnToDesc( msDesc, MSMainEnums::FLOAT_DATA, 2 ) ;
2248  else if ( useData_ )
2249    MeasurementSet::addColumnToDesc( msDesc, MSMainEnums::DATA, 2 ) ;
2250
2251  SetupNewTable newtab( filename_, msDesc, Table::New ) ;
2252
2253  mstable_ = new MeasurementSet( newtab ) ;
2254
2255  TableColumn col ;
2256  if ( useFloatData_ )
2257    col.attach( *mstable_, "FLOAT_DATA" ) ;
2258  else if ( useData_ )
2259    col.attach( *mstable_, "DATA" ) ;
2260  col.rwKeywordSet().define( "UNIT", dunit ) ;
2261
2262  // create subtables
2263  TableDesc antennaDesc = MSAntenna::requiredTableDesc() ;
2264  SetupNewTable antennaTab( mstable_->antennaTableName(), antennaDesc, Table::New ) ;
2265  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::ANTENNA ), Table( antennaTab ) ) ;
2266
2267  TableDesc dataDescDesc = MSDataDescription::requiredTableDesc() ;
2268  SetupNewTable dataDescTab( mstable_->dataDescriptionTableName(), dataDescDesc, Table::New ) ;
2269  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::DATA_DESCRIPTION ), Table( dataDescTab ) ) ;
2270
2271  TableDesc dopplerDesc = MSDoppler::requiredTableDesc() ;
2272  SetupNewTable dopplerTab( mstable_->dopplerTableName(), dopplerDesc, Table::New ) ;
2273  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::DOPPLER ), Table( dopplerTab ) ) ;
2274
2275  TableDesc feedDesc = MSFeed::requiredTableDesc() ;
2276  SetupNewTable feedTab( mstable_->feedTableName(), feedDesc, Table::New ) ;
2277  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::FEED ), Table( feedTab ) ) ;
2278
2279  TableDesc fieldDesc = MSField::requiredTableDesc() ;
2280  SetupNewTable fieldTab( mstable_->fieldTableName(), fieldDesc, Table::New ) ;
2281  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::FIELD ), Table( fieldTab ) ) ;
2282
2283  TableDesc flagCmdDesc = MSFlagCmd::requiredTableDesc() ;
2284  SetupNewTable flagCmdTab( mstable_->flagCmdTableName(), flagCmdDesc, Table::New ) ;
2285  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::FLAG_CMD ), Table( flagCmdTab ) ) ;
2286
2287  TableDesc freqOffsetDesc = MSFreqOffset::requiredTableDesc() ;
2288  SetupNewTable freqOffsetTab( mstable_->freqOffsetTableName(), freqOffsetDesc, Table::New ) ;
2289  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::FREQ_OFFSET ), Table( freqOffsetTab ) ) ;
2290
2291  TableDesc historyDesc = MSHistory::requiredTableDesc() ;
2292  SetupNewTable historyTab( mstable_->historyTableName(), historyDesc, Table::New ) ;
2293  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::HISTORY ), Table( historyTab ) ) ;
2294
2295  TableDesc observationDesc = MSObservation::requiredTableDesc() ;
2296  SetupNewTable observationTab( mstable_->observationTableName(), observationDesc, Table::New ) ;
2297  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::OBSERVATION ), Table( observationTab ) ) ;
2298
2299  TableDesc pointingDesc = MSPointing::requiredTableDesc() ;
2300  SetupNewTable pointingTab( mstable_->pointingTableName(), pointingDesc, Table::New ) ;
2301  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::POINTING ), Table( pointingTab ) ) ;
2302
2303  TableDesc polarizationDesc = MSPolarization::requiredTableDesc() ;
2304  SetupNewTable polarizationTab( mstable_->polarizationTableName(), polarizationDesc, Table::New ) ;
2305  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::POLARIZATION ), Table( polarizationTab ) ) ;
2306
2307  TableDesc processorDesc = MSProcessor::requiredTableDesc() ;
2308  SetupNewTable processorTab( mstable_->processorTableName(), processorDesc, Table::New ) ;
2309  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::PROCESSOR ), Table( processorTab ) ) ;
2310
2311  TableDesc sourceDesc = MSSource::requiredTableDesc() ;
2312  MSSource::addColumnToDesc( sourceDesc, MSSourceEnums::TRANSITION, 1 ) ;
2313  MSSource::addColumnToDesc( sourceDesc, MSSourceEnums::REST_FREQUENCY, 1 ) ;
2314  MSSource::addColumnToDesc( sourceDesc, MSSourceEnums::SYSVEL, 1 ) ;
2315  SetupNewTable sourceTab( mstable_->sourceTableName(), sourceDesc, Table::New ) ;
2316  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::SOURCE ), Table( sourceTab ) ) ;
2317
2318  TableDesc spwDesc = MSSpectralWindow::requiredTableDesc() ;
2319  SetupNewTable spwTab( mstable_->spectralWindowTableName(), spwDesc, Table::New ) ;
2320  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::SPECTRAL_WINDOW ), Table( spwTab ) ) ;
2321
2322  TableDesc stateDesc = MSState::requiredTableDesc() ;
2323  SetupNewTable stateTab( mstable_->stateTableName(), stateDesc, Table::New ) ;
2324  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::STATE ), Table( stateTab ) ) ;
2325
2326  TableDesc sysCalDesc = MSSysCal::requiredTableDesc() ;
2327  if ( tcalSpec_ )
2328    MSSysCal::addColumnToDesc( sysCalDesc, MSSysCalEnums::TCAL_SPECTRUM, 2 ) ;
2329  else
2330    MSSysCal::addColumnToDesc( sysCalDesc, MSSysCalEnums::TCAL, 1 ) ;
2331  if ( tsysSpec_ )
2332    MSSysCal::addColumnToDesc( sysCalDesc, MSSysCalEnums::TSYS_SPECTRUM, 2 ) ;
2333  else
2334    MSSysCal::addColumnToDesc( sysCalDesc, MSSysCalEnums::TSYS, 1 ) ;
2335  SetupNewTable sysCalTab( mstable_->sysCalTableName(), sysCalDesc, Table::New ) ;
2336  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::SYSCAL ), Table( sysCalTab ) ) ;
2337
2338  TableDesc weatherDesc = MSWeather::requiredTableDesc() ;
2339  MSWeather::addColumnToDesc( weatherDesc, MSWeatherEnums::TEMPERATURE ) ;
2340  MSWeather::addColumnToDesc( weatherDesc, MSWeatherEnums::PRESSURE ) ;
2341  MSWeather::addColumnToDesc( weatherDesc, MSWeatherEnums::REL_HUMIDITY ) ;
2342  MSWeather::addColumnToDesc( weatherDesc, MSWeatherEnums::WIND_SPEED ) ;
2343  MSWeather::addColumnToDesc( weatherDesc, MSWeatherEnums::WIND_DIRECTION ) ;
2344  SetupNewTable weatherTab( mstable_->weatherTableName(), weatherDesc, Table::New ) ;
2345  mstable_->rwKeywordSet().defineTable( MeasurementSet::keywordName( MeasurementSet::WEATHER ), Table( weatherTab ) ) ;
2346
2347  mstable_->initRefs() ;
2348
2349//   double endSec = mathutil::gettimeofday_sec() ;
2350//   os_ << "end MSWriter::setupMS() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2351}
2352
2353void MSWriter::fillObservation()
2354{
2355  //double startSec = mathutil::gettimeofday_sec() ;
2356  //os_ << "start MSWriter::fillObservation() startSec=" << startSec << LogIO::POST ;
2357
2358  // only 1 row
2359  mstable_->observation().addRow( 1, True ) ;
2360  MSObservationColumns msObsCols( mstable_->observation() ) ;
2361  msObsCols.observer().put( 0, header_.observer ) ;
2362  // tentatively put antennaname (from ANTENNA subtable)
2363  String hAntennaName = header_.antennaname ;
2364  String::size_type pos = hAntennaName.find( "//" ) ;
2365  String telescopeName ;
2366  if ( pos != String::npos ) {
2367    telescopeName = hAntennaName.substr( 0, pos ) ;
2368  }
2369  else {
2370    pos = hAntennaName.find( "@" ) ;
2371    telescopeName = hAntennaName.substr( 0, pos ) ;
2372  }
2373//   os_ << "telescopeName = " << telescopeName << LogIO::POST ;
2374  msObsCols.telescopeName().put( 0, telescopeName ) ;
2375  msObsCols.project().put( 0, header_.project ) ;
2376  //ScalarMeasColumn<MEpoch> timeCol( table_->table().sort("TIME"), "TIME" ) ;
2377  Table sortedtable = table_->table().sort("TIME") ;
2378  ScalarMeasColumn<MEpoch> timeCol( sortedtable, "TIME" ) ;
2379  Vector<MEpoch> trange( 2 ) ;
2380  trange[0] = timeCol( 0 ) ;
2381  trange[1] = timeCol( table_->nrow()-1 ) ;
2382  msObsCols.timeRangeMeas().put( 0, trange ) ;
2383
2384  //double endSec = mathutil::gettimeofday_sec() ;
2385  //os_ << "end MSWriter::fillObservation() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2386}
2387
2388void MSWriter::antennaProperty( String &name, String &m, String &t, Double &d )
2389{
2390  name.upcase() ;
2391 
2392  m = "ALT-AZ" ;
2393  t = "GROUND-BASED" ;
2394  if ( name.matches( Regex( "DV[0-9]+$" ) )
2395       || name.matches( Regex( "DA[0-9]+$" ) )
2396       || name.matches( Regex( "PM[0-9]+$" ) ) )
2397    d = 12.0 ;
2398  else if ( name.matches( Regex( "CM[0-9]+$" ) ) )
2399    d = 7.0 ;
2400  else if ( name.contains( "GBT" ) )
2401    d = 104.9 ;
2402  else if ( name.contains( "MOPRA" ) )
2403    d = 22.0 ;
2404  else if ( name.contains( "PKS" ) || name.contains( "PARKS" ) )
2405    d = 64.0 ;
2406  else if ( name.contains( "TIDBINBILLA" ) )
2407    d = 70.0 ;
2408  else if ( name.contains( "CEDUNA" ) )
2409    d = 30.0 ;
2410  else if ( name.contains( "HOBART" ) )
2411    d = 26.0 ;
2412  else if ( name.contains( "APEX" ) )
2413    d = 12.0 ;
2414  else if ( name.contains( "ASTE" ) )
2415    d = 10.0 ;
2416  else if ( name.contains( "NRO" ) )
2417    d = 45.0 ;
2418  else
2419    d = 1.0 ;
2420}
2421
2422void MSWriter::fillAntenna()
2423{
2424  //double startSec = mathutil::gettimeofday_sec() ;
2425  //os_ << "start MSWriter::fillAntenna() startSec=" << startSec << LogIO::POST ;
2426
2427  // only 1 row
2428  Table anttab = mstable_->antenna() ;
2429  anttab.addRow( 1, True ) ;
2430 
2431  Table &table = table_->table() ;
2432  const TableRecord &keys = table.keywordSet() ;
2433  String hAntName = keys.asString( "AntennaName" ) ;
2434  String::size_type pos = hAntName.find( "//" ) ;
2435  String antennaName ;
2436  String stationName ;
2437  if ( pos != String::npos ) {
2438    stationName = hAntName.substr( 0, pos ) ;
2439    hAntName = hAntName.substr( pos+2 ) ;
2440  }
2441  pos = hAntName.find( "@" ) ;
2442  if ( pos != String::npos ) {
2443    antennaName = hAntName.substr( 0, pos ) ;
2444    stationName = hAntName.substr( pos+1 ) ;
2445  }
2446  else {
2447    antennaName = hAntName ;
2448  }
2449  Vector<Double> antpos = keys.asArrayDouble( "AntennaPosition" ) ;
2450 
2451  String mount, atype ;
2452  Double diameter ;
2453  antennaProperty( antennaName, mount, atype, diameter ) ;
2454 
2455  TableRow tr( anttab ) ;
2456  TableRecord &r = tr.record() ;
2457  RecordFieldPtr<String> nameRF( r, "NAME" ) ;
2458  RecordFieldPtr<String> stationRF( r, "STATION" ) ;
2459  RecordFieldPtr<String> mountRF( r, "MOUNT" ) ;
2460  RecordFieldPtr<String> typeRF( r, "TYPE" ) ;
2461  RecordFieldPtr<Double> dishDiameterRF( r, "DISH_DIAMETER" ) ;
2462  RecordFieldPtr< Vector<Double> > positionRF( r, "POSITION" ) ;
2463  *nameRF = antennaName ;
2464  *mountRF = mount ;
2465  *typeRF = atype ;
2466  *dishDiameterRF = diameter ;
2467  *positionRF = antpos ;
2468  *stationRF = stationName ;
2469 
2470  tr.put( 0 ) ;
2471
2472  //double endSec = mathutil::gettimeofday_sec() ;
2473  //os_ << "end MSWriter::fillAntenna() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2474}
2475 
2476void MSWriter::fillProcessor()
2477{
2478//   double startSec = mathutil::gettimeofday_sec() ;
2479//   os_ << "start MSWriter::fillProcessor() startSec=" << startSec << LogIO::POST ;
2480 
2481  // only add empty 1 row
2482  MSProcessor msProc = mstable_->processor() ;
2483  msProc.addRow( 1, True ) ;
2484
2485//   double endSec = mathutil::gettimeofday_sec() ;
2486//   os_ << "end MSWriter::fillProcessor() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2487}
2488
2489void MSWriter::fillSource()
2490{
2491//   double startSec = mathutil::gettimeofday_sec() ;
2492//   os_ << "start MSWriter::fillSource() startSec=" << startSec << LogIO::POST ;
2493 
2494  // access to MS SOURCE subtable
2495  MSSource msSrc = mstable_->source() ;
2496
2497  // access to MOLECULE subtable
2498  STMolecules stm = table_->molecules() ;
2499
2500  Int srcId = 0 ;
2501  Vector<Double> restFreq ;
2502  Vector<String> molName ;
2503  Vector<String> fMolName ;
2504
2505  // row based
2506  TableRow row( msSrc ) ;
2507  TableRecord &rec = row.record() ;
2508  RecordFieldPtr<Int> srcidRF( rec, "SOURCE_ID" ) ;
2509  RecordFieldPtr<String> nameRF( rec, "NAME" ) ;
2510  RecordFieldPtr< Array<Double> > srcpmRF( rec, "PROPER_MOTION" ) ;
2511  RecordFieldPtr< Array<Double> > srcdirRF( rec, "DIRECTION" ) ;
2512  RecordFieldPtr<Int> numlineRF( rec, "NUM_LINES" ) ;
2513  RecordFieldPtr< Array<Double> > restfreqRF( rec, "REST_FREQUENCY" ) ;
2514  RecordFieldPtr< Array<Double> > sysvelRF( rec, "SYSVEL" ) ;
2515  RecordFieldPtr< Array<String> > transitionRF( rec, "TRANSITION" ) ;
2516  RecordFieldPtr<Double> timeRF( rec, "TIME" ) ;
2517  RecordFieldPtr<Double> intervalRF( rec, "INTERVAL" ) ;
2518  RecordFieldPtr<Int> spwidRF( rec, "SPECTRAL_WINDOW_ID" ) ;
2519
2520  //
2521  // ITERATION: SRCNAME
2522  //
2523  TableIterator iter0( table_->table(), "SRCNAME" ) ;
2524  while( !iter0.pastEnd() ) {
2525    //Table t0( iter0.table() ) ;
2526    Table t0 =  iter0.table()  ;
2527
2528    // get necessary information
2529    ROScalarColumn<String> srcNameCol( t0, "SRCNAME" ) ;
2530    String srcName = srcNameCol( 0 ) ;
2531    ROArrayColumn<Double> sharedDArrRCol( t0, "SRCPROPERMOTION" ) ;
2532    Vector<Double> srcPM = sharedDArrRCol( 0 ) ;
2533    sharedDArrRCol.attach( t0, "SRCDIRECTION" ) ;
2534    Vector<Double> srcDir = sharedDArrRCol( 0 ) ;
2535    ROScalarColumn<Double> srcVelCol( t0, "SRCVELOCITY" ) ;
2536    Double srcVel = srcVelCol( 0 ) ;
2537    srcRec_.define( srcName, srcId ) ;
2538
2539    // NAME
2540    *nameRF = srcName ;
2541
2542    // SOURCE_ID
2543    *srcidRF = srcId ;
2544
2545    // PROPER_MOTION
2546    *srcpmRF = srcPM ;
2547   
2548    // DIRECTION
2549    *srcdirRF = srcDir ;
2550
2551    //
2552    // ITERATION: MOLECULE_ID
2553    //
2554    TableIterator iter1( t0, "MOLECULE_ID" ) ;
2555    while( !iter1.pastEnd() ) {
2556      //Table t1( iter1.table() ) ;
2557      Table t1 = iter1.table() ;
2558
2559      // get necessary information
2560      ROScalarColumn<uInt> molIdCol( t1, "MOLECULE_ID" ) ;
2561      uInt molId = molIdCol( 0 ) ;
2562      stm.getEntry( restFreq, molName, fMolName, molId ) ;
2563
2564      uInt numFreq = restFreq.size() ;
2565     
2566      // NUM_LINES
2567      *numlineRF = numFreq ;
2568
2569      // REST_FREQUENCY
2570      *restfreqRF = restFreq ;
2571
2572      // TRANSITION
2573      //*transitionRF = fMolName ;
2574      Vector<String> transition ;
2575      if ( fMolName.size() != 0 ) {
2576        transition = fMolName ;
2577      }
2578      else if ( molName.size() != 0 ) {
2579        transition = molName ;
2580      }
2581      else {
2582        transition.resize( numFreq ) ;
2583        transition = "" ;
2584      }
2585      *transitionRF = transition ;
2586
2587      // SYSVEL
2588      Vector<Double> sysvelArr( numFreq, srcVel ) ;
2589      *sysvelRF = sysvelArr ;
2590
2591      //
2592      // ITERATION: IFNO
2593      //
2594      TableIterator iter2( t1, "IFNO" ) ;
2595      while( !iter2.pastEnd() ) {
2596        //Table t2( iter2.table() ) ;
2597        Table t2 = iter2.table() ;
2598        uInt nrow = msSrc.nrow() ;
2599
2600        // get necessary information
2601        ROScalarColumn<uInt> ifNoCol( t2, "IFNO" ) ;
2602        uInt ifno = ifNoCol( 0 ) ; // IFNO = SPECTRAL_WINDOW_ID
2603        Double midTime ;
2604        Double interval ;
2605        getValidTimeRange( midTime, interval, t2 ) ;
2606
2607        // fill SPECTRAL_WINDOW_ID
2608        *spwidRF = ifno ;
2609
2610        // fill TIME, INTERVAL
2611        *timeRF = midTime ;
2612        *intervalRF = interval ;
2613
2614        // add row
2615        msSrc.addRow( 1, True ) ;
2616        row.put( nrow ) ;
2617
2618        iter2.next() ;
2619      }
2620
2621      iter1.next() ;
2622    }
2623
2624    // increment srcId if SRCNAME changed
2625    srcId++ ;
2626
2627    iter0.next() ;
2628  }
2629
2630//   double endSec = mathutil::gettimeofday_sec() ;
2631//   os_ << "end MSWriter::fillSource() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2632}
2633
2634void MSWriter::fillWeather()
2635{
2636//   double startSec = mathutil::gettimeofday_sec() ;
2637//   os_ << "start MSWriter::fillWeather() startSec=" << startSec << LogIO::POST ;
2638
2639  // access to MS WEATHER subtable
2640  MSWeather msw = mstable_->weather() ;
2641
2642  // access to WEATHER subtable
2643  Table stw = table_->weather().table() ;
2644  uInt nrow = stw.nrow() ;
2645
2646  if ( nrow == 0 )
2647    return ;
2648
2649  msw.addRow( nrow, True ) ;
2650  MSWeatherColumns mswCols( msw ) ;
2651
2652  // ANTENNA_ID is always 0
2653  Vector<Int> antIdArr( nrow, 0 ) ;
2654  mswCols.antennaId().putColumn( antIdArr ) ;
2655
2656  // fill weather status
2657  ROScalarColumn<Float> sharedFloatCol( stw, "TEMPERATURE" ) ;
2658  mswCols.temperature().putColumn( sharedFloatCol ) ;
2659  sharedFloatCol.attach( stw, "PRESSURE" ) ;
2660  mswCols.pressure().putColumn( sharedFloatCol ) ;
2661  sharedFloatCol.attach( stw, "HUMIDITY" ) ;
2662  mswCols.relHumidity().putColumn( sharedFloatCol ) ;
2663  sharedFloatCol.attach( stw, "WINDSPEED" ) ;
2664  mswCols.windSpeed().putColumn( sharedFloatCol ) ;
2665  sharedFloatCol.attach( stw, "WINDAZ" ) ;
2666  mswCols.windDirection().putColumn( sharedFloatCol ) ;
2667
2668  // fill TIME and INTERVAL
2669  Double midTime ;
2670  Double interval ;
2671  Vector<Double> intervalArr( nrow, 0.0 ) ;
2672  TableIterator iter( table_->table(), "WEATHER_ID" ) ;
2673  while( !iter.pastEnd() ) {
2674    //Table tab( iter.table() ) ;
2675    Table tab = iter.table() ;
2676
2677    ROScalarColumn<uInt> widCol( tab, "WEATHER_ID" ) ;
2678    uInt wid = widCol( 0 ) ;
2679
2680    getValidTimeRange( midTime, interval, tab ) ;
2681    mswCols.time().put( wid, midTime ) ;
2682    intervalArr[wid] = interval ;
2683
2684    iter.next() ;
2685  }
2686  mswCols.interval().putColumn( intervalArr ) ;
2687
2688//   double endSec = mathutil::gettimeofday_sec() ;
2689//   os_ << "end MSWriter::fillWeather() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2690}
2691
2692void MSWriter::fillSysCal()
2693{
2694  Table mssc = mstable_->sysCal() ;
2695
2696  {
2697    static const char *cols[] = {
2698      "BEAMNO", "IFNO", "TIME", "POLNO",
2699      NULL
2700    };
2701    static const TypeManagerImpl<uInt> tmUInt;
2702    static const TypeManagerImpl<Double> tmDouble;
2703    static const TypeManager *const tms[] = {
2704      &tmUInt, &tmUInt, &tmDouble, &tmUInt, NULL
2705    };
2706    //double t0 = mathutil::gettimeofday_sec() ;
2707    MSSysCalVisitor myVisitor(table_->table(),mssc);
2708    //double t1 = mathutil::gettimeofday_sec() ;
2709    //cout << "MSWriterVisitor(): elapsed time " << t1-t0 << " sec" << endl ;
2710    traverseTable(table_->table(), cols, tms, &myVisitor);
2711    //double t3 = mathutil::gettimeofday_sec() ;
2712    //cout << "traverseTable(): elapsed time " << t3-t2 << " sec" << endl ;
2713  }
2714 
2715}
2716
2717void MSWriter::getValidTimeRange( Double &me, Double &interval, Table &tab )
2718{
2719//   double startSec = mathutil::gettimeofday_sec() ;
2720//   os_ << "start MSWriter::getVaridTimeRange() startSec=" << startSec << LogIO::POST ;
2721
2722  // sort table
2723  //Table stab = tab.sort( "TIME" ) ;
2724
2725  ROScalarColumn<Double> timeCol( tab, "TIME" ) ;
2726  Vector<Double> timeArr = timeCol.getColumn() ;
2727  Double minTime ;
2728  Double maxTime ;
2729  minMax( minTime, maxTime, timeArr ) ;
2730  Double midTime = 0.5 * ( minTime + maxTime ) * 86400.0 ;
2731  // unit for TIME
2732  // Scantable: "d"
2733  // MS: "s"
2734  me = midTime ;
2735  interval = ( maxTime - minTime ) * 86400.0 ;
2736
2737//   double endSec = mathutil::gettimeofday_sec() ;
2738//   os_ << "end MSWriter::getValidTimeRange() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2739}
2740
2741void MSWriter::getValidTimeRange( Double &me, Double &interval, Vector<Double> &atime, Vector<Double> &ainterval )
2742{
2743//   double startSec = mathutil::gettimeofday_sec() ;
2744//   os_ << "start MSWriter::getVaridTimeRange() startSec=" << startSec << LogIO::POST ;
2745
2746  // sort table
2747  //Table stab = tab.sort( "TIME" ) ;
2748
2749  Double minTime ;
2750  Double maxTime ;
2751  minMax( minTime, maxTime, atime ) ;
2752  Double midTime = 0.5 * ( minTime + maxTime ) * 86400.0 ;
2753  // unit for TIME
2754  // Scantable: "d"
2755  // MS: "s"
2756  me = midTime ;
2757  interval = ( maxTime - minTime ) * 86400.0 + mean( ainterval ) ;
2758
2759//   double endSec = mathutil::gettimeofday_sec() ;
2760//   os_ << "end MSWriter::getValidTimeRange() endSec=" << endSec << " (" << endSec-startSec << "sec)" << LogIO::POST ;
2761}
2762
2763}
Note: See TracBrowser for help on using the repository browser.