source: trunk/src/SDMath.cc @ 270

Last change on this file since 270 was 270, checked in by kil064, 19 years ago

use new MaskedArray?(IPosition,IPOsition) slice operator
to simplyify some code. Also reuse function 'correctFromVector'
more to consolidate code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.4 KB
Line 
1//#---------------------------------------------------------------------------
2//# SDMath.cc: A collection of single dish mathematical operations
3//#---------------------------------------------------------------------------
4//# Copyright (C) 2004
5//# ATNF
6//#
7//# This program is free software; you can redistribute it and/or modify it
8//# under the terms of the GNU General Public License as published by the Free
9//# Software Foundation; either version 2 of the License, or (at your option)
10//# any later version.
11//#
12//# This program is distributed in the hope that it will be useful, but
13//# WITHOUT ANY WARRANTY; without even the implied warranty of
14//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15//# Public License for more details.
16//#
17//# You should have received a copy of the GNU General Public License along
18//# with this program; if not, write to the Free Software Foundation, Inc.,
19//# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
20//#
21//# Correspondence concerning this software should be addressed as follows:
22//#        Internet email: Malte.Marquarding@csiro.au
23//#        Postal address: Malte Marquarding,
24//#                        Australia Telescope National Facility,
25//#                        P.O. Box 76,
26//#                        Epping, NSW, 2121,
27//#                        AUSTRALIA
28//#
29//# $Id:
30//#---------------------------------------------------------------------------
31#include <vector>
32
33#include <casa/aips.h>
34#include <casa/BasicSL/String.h>
35#include <casa/Arrays/IPosition.h>
36#include <casa/Arrays/Array.h>
37#include <casa/Arrays/ArrayIter.h>
38#include <casa/Arrays/VectorIter.h>
39#include <casa/Arrays/ArrayMath.h>
40#include <casa/Arrays/ArrayLogical.h>
41#include <casa/Arrays/MaskedArray.h>
42#include <casa/Arrays/MaskArrMath.h>
43#include <casa/Arrays/MaskArrLogi.h>
44#include <casa/BasicMath/Math.h>
45#include <casa/Containers/Block.h>
46#include <casa/Exceptions.h>
47#include <casa/Quanta/Quantum.h>
48#include <casa/Quanta/Unit.h>
49#include <casa/Quanta/MVEpoch.h>
50#include <casa/Quanta/QC.h>
51#include <casa/Utilities/Assert.h>
52
53#include <coordinates/Coordinates/SpectralCoordinate.h>
54#include <coordinates/Coordinates/CoordinateSystem.h>
55#include <coordinates/Coordinates/CoordinateUtil.h>
56#include <coordinates/Coordinates/VelocityAligner.h>
57
58#include <lattices/Lattices/LatticeUtilities.h>
59#include <lattices/Lattices/RebinLattice.h>
60
61#include <measures/Measures/MEpoch.h>
62#include <measures/Measures/MDirection.h>
63#include <measures/Measures/MPosition.h>
64
65#include <scimath/Mathematics/VectorKernel.h>
66#include <scimath/Mathematics/Convolver.h>
67#include <scimath/Mathematics/InterpolateArray1D.h>
68#include <scimath/Functionals/Polynomial.h>
69
70#include <tables/Tables/Table.h>
71#include <tables/Tables/ScalarColumn.h>
72#include <tables/Tables/ArrayColumn.h>
73#include <tables/Tables/ReadAsciiTable.h>
74
75#include "MathUtils.h"
76#include "SDDefs.h"
77#include "SDContainer.h"
78#include "SDMemTable.h"
79
80#include "SDMath.h"
81
82using namespace casa;
83using namespace asap;
84
85
86SDMath::SDMath()
87{;}
88
89SDMath::SDMath(const SDMath& other)
90{
91
92// No state
93
94}
95
96SDMath& SDMath::operator=(const SDMath& other)
97{
98  if (this != &other) {
99// No state
100  }
101  return *this;
102}
103
104SDMath::~SDMath()
105{;}
106
107
108
109SDMemTable* SDMath::velocityAlignment (const SDMemTable& in) const
110{
111
112// Get velocity/frame info from Table
113
114   std::vector<std::string> info = in.getCoordInfo();
115   String velUnit(info[0]);
116   if (velUnit.length()==0) {
117      throw(AipsError("You have not set a velocity abcissa unit - use function set_unit"));
118   } else {
119      Unit velUnitU(velUnit);
120      if (velUnitU!=Unit(String("m/s"))) {
121         throw(AipsError("Specified abcissa unit is not consistent with km/s - use function set_unit"));
122      }
123   }
124//
125   String dopplerStr(info[2]);
126   String velSystemStr(info[1]);
127   String velBaseSystemStr(info[3]);
128   if (velBaseSystemStr==velSystemStr) {
129      throw(AipsError("You have not set a velocity frame different from the initial - use function set_freqframe"));
130   }
131//
132   MFrequency::Types velSystem;
133   MFrequency::getType(velSystem, velSystemStr);
134   MDoppler::Types doppler;
135   MDoppler::getType(doppler, dopplerStr);
136
137// Decide on alignment Epoch
138
139// Do it
140
141   return velocityAlign (in, velSystem, velUnit, doppler);
142}
143
144
145
146CountedPtr<SDMemTable> SDMath::average(const Block<CountedPtr<SDMemTable> >& in,
147                                       const Vector<Bool>& mask, Bool scanAv,
148                                       const String& weightStr, Bool alignVelocity) const
149//
150// Weighted averaging of spectra from one or more Tables.
151//
152{
153
154// Convert weight type
155 
156  WeightType wtType = NONE;
157  convertWeightString(wtType, weightStr);
158
159// Create output Table by cloning from the first table
160
161  SDMemTable* pTabOut = new SDMemTable(*in[0],True);
162
163// Setup
164
165  IPosition shp = in[0]->rowAsMaskedArray(0).shape();      // Must not change
166  Array<Float> arr(shp);
167  Array<Bool> barr(shp);
168  const Bool useMask = (mask.nelements() == shp(asap::ChanAxis));
169
170// Columns from Tables
171
172  ROArrayColumn<Float> tSysCol;
173  ROScalarColumn<Double> mjdCol;
174  ROScalarColumn<String> srcNameCol;
175  ROScalarColumn<Double> intCol;
176  ROArrayColumn<uInt> fqIDCol;
177
178// Create accumulation MaskedArray. We accumulate for each channel,if,pol,beam
179// Note that the mask of the accumulation array will ALWAYS remain ALL True.
180// The MA is only used so that when data which is masked Bad is added to it,
181// that data does not contribute.
182
183  Array<Float> zero(shp);
184  zero=0.0;
185  Array<Bool> good(shp);
186  good = True;
187  MaskedArray<Float> sum(zero,good);
188
189// Counter arrays
190
191  Array<Float> nPts(shp);             // Number of points
192  nPts = 0.0;
193  Array<Float> nInc(shp);             // Increment
194  nInc = 1.0;
195
196// Create accumulation Array for variance. We accumulate for
197// each if,pol,beam, but average over channel.  So we need
198// a shape with one less axis dropping channels.
199
200  const uInt nAxesSub = shp.nelements() - 1;
201  IPosition shp2(nAxesSub);
202  for (uInt i=0,j=0; i<(nAxesSub+1); i++) {
203     if (i!=asap::ChanAxis) {
204       shp2(j) = shp(i);
205       j++;
206     }
207  }
208  Array<Float> sumSq(shp2);
209  sumSq = 0.0;
210  IPosition pos2(nAxesSub,0);                        // For indexing
211
212// Time-related accumulators
213
214  Double time;
215  Double timeSum = 0.0;
216  Double intSum = 0.0;
217  Double interval = 0.0;
218
219// To get the right shape for the Tsys accumulator we need to
220// access a column from the first table.  The shape of this
221// array must not change
222
223  Array<Float> tSysSum;
224  {
225    const Table& tabIn = in[0]->table();
226    tSysCol.attach(tabIn,"TSYS");
227    tSysSum.resize(tSysCol.shape(0));
228  }
229  tSysSum =0.0;
230  Array<Float> tSys;
231
232// Scan and row tracking
233
234  Int oldScanID = 0;
235  Int outScanID = 0;
236  Int scanID = 0;
237  Int rowStart = 0;
238  Int nAccum = 0;
239  Int tableStart = 0;
240
241// Source and FreqID
242
243  String sourceName, oldSourceName, sourceNameStart;
244  Vector<uInt> freqID, freqIDStart, oldFreqID;
245
246// Loop over tables
247
248  Float fac = 1.0;
249  const uInt nTables = in.nelements();
250  for (uInt iTab=0; iTab<nTables; iTab++) {
251
252// Should check that the frequency tables don't change if doing VelocityAlignment
253
254// Attach columns to Table
255
256     const Table& tabIn = in[iTab]->table();
257     tSysCol.attach(tabIn, "TSYS");
258     mjdCol.attach(tabIn, "TIME");
259     srcNameCol.attach(tabIn, "SRCNAME");
260     intCol.attach(tabIn, "INTERVAL");
261     fqIDCol.attach(tabIn, "FREQID");
262
263// Loop over rows in Table
264
265     const uInt nRows = in[iTab]->nRow();
266     for (uInt iRow=0; iRow<nRows; iRow++) {
267
268// Check conformance
269
270        IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();
271        if (!shp.isEqual(shp2)) {
272           throw (AipsError("Shapes for all rows must be the same"));
273        }
274
275// If we are not doing scan averages, make checks for source and
276// frequency setup and warn if averaging across them
277
278// Get copy of Scan Container for this row
279
280        SDContainer sc = in[iTab]->getSDContainer(iRow);
281        scanID = sc.scanid;
282
283// Get quantities from columns
284
285        srcNameCol.getScalar(iRow, sourceName);
286        mjdCol.get(iRow, time);
287        tSysCol.get(iRow, tSys);
288        intCol.get(iRow, interval);
289        fqIDCol.get(iRow, freqID);
290
291// Initialize first source and freqID
292
293        if (iRow==0 && iTab==0) {
294          sourceNameStart = sourceName;
295          freqIDStart = freqID;
296        }
297
298// If we are doing scan averages, see if we are at the end of an
299// accumulation period (scan).  We must check soutce names too,
300// since we might have two tables with one scan each but different
301// source names; we shouldn't average different sources together
302
303        if (scanAv && ( (scanID != oldScanID)  ||
304                        (iRow==0 && iTab>0 && sourceName!=oldSourceName))) {
305
306// Normalize data in 'sum' accumulation array according to weighting scheme
307
308           normalize(sum, sumSq, nPts, wtType, asap::ChanAxis, nAxesSub);
309
310// Fill scan container. The source and freqID come from the
311// first row of the first table that went into this average (
312// should be the same for all rows in the scan average)
313
314           Float nR(nAccum);
315           fillSDC(sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
316                    timeSum/nR, intSum, sourceNameStart, freqIDStart);
317
318// Write container out to Table
319
320           pTabOut->putSDContainer(sc);
321
322// Reset accumulators
323
324           sum = 0.0;
325           sumSq = 0.0;
326           nAccum = 0;
327//
328           tSysSum =0.0;
329           timeSum = 0.0;
330           intSum = 0.0;
331           nPts = 0.0;
332
333// Increment
334
335           rowStart = iRow;              // First row for next accumulation
336           tableStart = iTab;            // First table for next accumulation
337           sourceNameStart = sourceName; // First source name for next accumulation
338           freqIDStart = freqID;         // First FreqID for next accumulation
339//
340           oldScanID = scanID;
341           outScanID += 1;               // Scan ID for next accumulation period
342        }
343
344// Accumulate
345
346        accumulate(timeSum, intSum, nAccum, sum, sumSq, nPts, tSysSum,
347                    tSys, nInc, mask, time, interval, in, iTab, iRow, asap::ChanAxis,
348                    nAxesSub, useMask, wtType);
349//
350       oldSourceName = sourceName;
351       oldFreqID = freqID;
352     }
353  }
354
355// OK at this point we have accumulation data which is either
356//   - accumulated from all tables into one row
357// or
358//   - accumulated from the last scan average
359//
360// Normalize data in 'sum' accumulation array according to weighting scheme
361  normalize(sum, sumSq, nPts, wtType, asap::ChanAxis, nAxesSub);
362
363// Create and fill container.  The container we clone will be from
364// the last Table and the first row that went into the current
365// accumulation.  It probably doesn't matter that much really...
366
367  Float nR(nAccum);
368  SDContainer sc = in[tableStart]->getSDContainer(rowStart);
369  fillSDC(sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
370           timeSum/nR, intSum, sourceNameStart, freqIDStart);
371  pTabOut->putSDContainer(sc);
372//
373  return CountedPtr<SDMemTable>(pTabOut);
374}
375
376
377
378CountedPtr<SDMemTable> SDMath::binaryOperate (const CountedPtr<SDMemTable>& left,
379                                              const CountedPtr<SDMemTable>& right,
380                                              const String& op, Bool preserve)  const
381{
382
383// Check operator
384
385  String op2(op);
386  op2.upcase();
387  uInt what = 0;
388  if (op2=="ADD") {
389     what = 0;
390  } else if (op2=="SUB") {
391     what = 1;
392  } else if (op2=="MUL") {
393     what = 2;
394  } else if (op2=="DIV") {
395     what = 3;
396  } else if (op2=="QUOTIENT") {
397     what = 4;
398  } else {
399    throw( AipsError("Unrecognized operation"));
400  }
401
402// Check rows
403
404  const uInt nRowLeft = left->nRow();
405  const uInt nRowRight = right->nRow();
406  Bool ok = (nRowRight==1&&nRowLeft>0) ||
407            (nRowRight>=1&&nRowLeft==nRowRight);
408  if (!ok) {
409     throw (AipsError("The right Scan Table can have one row or the same number of rows as the left Scan Table"));
410  }
411
412// Input Tables
413
414  const Table& tLeft = left->table();
415  const Table& tRight = right->table();
416
417// TSys columns
418
419  ROArrayColumn<Float> tSysLeft(tLeft, "TSYS");
420  ROArrayColumn<Float> tSysRight(tRight, "TSYS");
421
422// First row for right
423
424  Array<Float> tSysLeftArr, tSysRightArr;
425  tSysRight.get(0, tSysRightArr);
426  MaskedArray<Float>* pMRight = new MaskedArray<Float>(right->rowAsMaskedArray(0));
427  IPosition shpRight = pMRight->shape();
428
429// Output Table cloned from left
430
431  SDMemTable* pTabOut = new SDMemTable(*left, True);
432
433// Loop over rows
434
435  for (uInt i=0; i<nRowLeft; i++) {
436
437// Get data
438
439     MaskedArray<Float> mLeft(left->rowAsMaskedArray(i));
440     IPosition shpLeft = mLeft.shape();
441     tSysLeft.get(i, tSysLeftArr);
442//
443     if (nRowRight>1) {
444        delete pMRight;
445        pMRight = new MaskedArray<Float>(right->rowAsMaskedArray(i));
446        shpRight = pMRight->shape();
447        tSysRight.get(i, tSysRightArr);
448     }
449//
450     if (!shpRight.isEqual(shpLeft)) {
451        throw(AipsError("left and right scan tables are not conformant"));
452     }
453     if (!tSysRightArr.shape().isEqual(tSysRightArr.shape())) {
454        throw(AipsError("left and right Tsys data are not conformant"));
455     }
456     if (!shpRight.isEqual(tSysRightArr.shape())) {
457        throw(AipsError("left and right scan tables are not conformant"));
458     }
459
460// Make container
461
462     SDContainer sc = left->getSDContainer(i);
463
464// Operate on data and TSys
465
466     if (what==0) {                               
467        MaskedArray<Float> tmp = mLeft + *pMRight;
468        putDataInSDC(sc, tmp.getArray(), tmp.getMask());
469        sc.putTsys(tSysLeftArr+tSysRightArr);
470     } else if (what==1) {
471        MaskedArray<Float> tmp = mLeft - *pMRight;
472        putDataInSDC(sc, tmp.getArray(), tmp.getMask());
473        sc.putTsys(tSysLeftArr-tSysRightArr);
474     } else if (what==2) {
475        MaskedArray<Float> tmp = mLeft * *pMRight;
476        putDataInSDC(sc, tmp.getArray(), tmp.getMask());
477        sc.putTsys(tSysLeftArr*tSysRightArr);
478     } else if (what==3) {
479        MaskedArray<Float> tmp = mLeft / *pMRight;
480        putDataInSDC(sc, tmp.getArray(), tmp.getMask());
481        sc.putTsys(tSysLeftArr/tSysRightArr);
482     } else if (what==4) {
483        if (preserve) {     
484           MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) - tSysRightArr;
485           putDataInSDC(sc, tmp.getArray(), tmp.getMask());
486        } else {
487           MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) - tSysLeftArr;
488           putDataInSDC(sc, tmp.getArray(), tmp.getMask());
489        }
490        sc.putTsys(tSysRightArr);
491     }
492
493// Put new row in output Table
494
495     pTabOut->putSDContainer(sc);
496  }
497  if (pMRight) delete pMRight;
498//
499  return CountedPtr<SDMemTable>(pTabOut);
500}
501
502
503
504std::vector<float> SDMath::statistic(const CountedPtr<SDMemTable>& in,
505                                     const Vector<Bool>& mask,
506                                     const String& which, Int row) const
507//
508// Perhaps iteration over pol/beam/if should be in here
509// and inside the nrow iteration ?
510//
511{
512  const uInt nRow = in->nRow();
513
514// Specify cursor location
515
516  IPosition start, end;
517  getCursorLocation(start, end, *in);
518
519// Loop over rows
520
521  const uInt nEl = mask.nelements();
522  uInt iStart = 0;
523  uInt iEnd = in->nRow()-1;
524// 
525  if (row>=0) {
526     iStart = row;
527     iEnd = row;
528  }
529//
530  std::vector<float> result(iEnd-iStart+1);
531  for (uInt ii=iStart; ii <= iEnd; ++ii) {
532
533// Get row and deconstruct
534
535     MaskedArray<Float> marr(in->rowAsMaskedArray(ii));
536     Array<Float> arr = marr.getArray();
537     Array<Bool> barr = marr.getMask();
538
539// Access desired piece of data
540
541     Array<Float> v((arr(start,end)).nonDegenerate());
542     Array<Bool> m((barr(start,end)).nonDegenerate());
543
544// Apply OTF mask
545
546     MaskedArray<Float> tmp;
547     if (m.nelements()==nEl) {
548       tmp.setData(v,m&&mask);
549     } else {
550       tmp.setData(v,m);
551     }
552
553// Get statistic
554
555     result[ii-iStart] = mathutil::statistics(which, tmp);
556  }
557//
558  return result;
559}
560
561
562SDMemTable* SDMath::bin(const SDMemTable& in, Int width) const
563{
564  SDHeader sh = in.getSDHeader();
565  SDMemTable* pTabOut = new SDMemTable(in, True);
566
567// Bin up SpectralCoordinates
568
569  IPosition factors(1);
570  factors(0) = width;
571  for (uInt j=0; j<in.nCoordinates(); ++j) {
572    CoordinateSystem cSys;
573    cSys.addCoordinate(in.getCoordinate(j));
574    CoordinateSystem cSysBin =
575      CoordinateUtil::makeBinnedCoordinateSystem(factors, cSys, False);
576//
577    SpectralCoordinate sCBin = cSysBin.spectralCoordinate(0);
578    pTabOut->setCoordinate(sCBin, j);
579  }
580
581// Use RebinLattice to find shape
582
583  IPosition shapeIn(1,sh.nchan);
584  IPosition shapeOut = RebinLattice<Float>::rebinShape(shapeIn, factors);
585  sh.nchan = shapeOut(0);
586  pTabOut->putSDHeader(sh);
587
588
589// Loop over rows and bin along channel axis
590 
591  for (uInt i=0; i < in.nRow(); ++i) {
592    SDContainer sc = in.getSDContainer(i);
593//
594    Array<Float> tSys(sc.getTsys());                           // Get it out before sc changes shape
595
596// Bin up spectrum
597
598    MaskedArray<Float> marr(in.rowAsMaskedArray(i));
599    MaskedArray<Float> marrout;
600    LatticeUtilities::bin(marrout, marr, asap::ChanAxis, width);
601
602// Put back the binned data and flags
603
604    IPosition ip2 = marrout.shape();
605    sc.resize(ip2);
606//
607    putDataInSDC(sc, marrout.getArray(), marrout.getMask());
608
609// Bin up Tsys. 
610
611    Array<Bool> allGood(tSys.shape(),True);
612    MaskedArray<Float> tSysIn(tSys, allGood, True);
613//
614    MaskedArray<Float> tSysOut;   
615    LatticeUtilities::bin(tSysOut, tSysIn, asap::ChanAxis, width);
616    sc.putTsys(tSysOut.getArray());
617//
618    pTabOut->putSDContainer(sc);
619  }
620  return pTabOut;
621}
622
623SDMemTable* SDMath::unaryOperate(const SDMemTable& in, Float val, Bool doAll,
624                                 uInt what) const
625//
626// what = 0   Multiply
627//        1   Add
628{
629   SDMemTable* pOut = new SDMemTable(in,False);
630   const Table& tOut = pOut->table();
631   ArrayColumn<Float> spec(tOut,"SPECTRA"); 
632//
633   if (doAll) {
634      for (uInt i=0; i < tOut.nrow(); i++) {
635         MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
636//
637         if (what==0) {
638            dataIn  *= val;
639         } else if (what==1) {
640            dataIn += val;
641         }
642//
643         spec.put(i, dataIn.getArray());
644      }
645   } else {
646
647// Get cursor location
648
649      IPosition start, end;
650      getCursorLocation(start, end, in);
651//
652      for (uInt i=0; i < tOut.nrow(); i++) {
653         MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
654         MaskedArray<Float> dataIn2 = dataIn(start,end);    // Reference
655//
656         if (what==0) {
657            dataIn2 *= val;
658         } else if (what==1) {
659            dataIn2 += val;
660         }
661//
662         spec.put(i, dataIn.getArray());
663      }
664   }
665//
666   return pOut;
667}
668
669
670
671SDMemTable* SDMath::averagePol(const SDMemTable& in, const Vector<Bool>& mask) const
672//
673// Average all polarizations together, weighted by variance
674//
675{
676//   WeightType wtType = NONE;
677//   convertWeightString(wtType, weight);
678
679   const uInt nRows = in.nRow();
680
681// Create output Table and reshape number of polarizations
682
683  Bool clear=True;
684  SDMemTable* pTabOut = new SDMemTable(in, clear);
685  SDHeader header = pTabOut->getSDHeader();
686  header.npol = 1;
687  pTabOut->putSDHeader(header);
688
689// Shape of input and output data
690
691  const IPosition& shapeIn = in.rowAsMaskedArray(0u, False).shape();
692  IPosition shapeOut(shapeIn);
693  shapeOut(asap::PolAxis) = 1;                          // Average all polarizations
694//
695  const uInt nChan = shapeIn(asap::ChanAxis);
696  const IPosition vecShapeOut(4,1,1,1,nChan);     // A multi-dim form of a Vector shape
697  IPosition start(4), end(4);
698
699// Output arrays
700
701  Array<Float> outData(shapeOut, 0.0);
702  Array<Bool> outMask(shapeOut, True);
703  const IPosition axes(2, asap::PolAxis, asap::ChanAxis);              // pol-channel plane
704//
705  const Bool useMask = (mask.nelements() == shapeIn(asap::ChanAxis));
706
707// Loop over rows
708
709   for (uInt iRow=0; iRow<nRows; iRow++) {
710
711// Get data for this row
712
713      MaskedArray<Float> marr(in.rowAsMaskedArray(iRow));
714      Array<Float>& arr = marr.getRWArray();
715      const Array<Bool>& barr = marr.getMask();
716
717// Make iterators to iterate by pol-channel planes
718
719      ReadOnlyArrayIterator<Float> itDataPlane(arr, axes);
720      ReadOnlyArrayIterator<Bool> itMaskPlane(barr, axes);
721
722// Accumulations
723
724      Float fac = 1.0;
725      Vector<Float> vecSum(nChan,0.0);
726
727// Iterate through data by pol-channel planes
728
729      while (!itDataPlane.pastEnd()) {
730
731// Iterate through plane by polarization  and accumulate Vectors
732
733        Vector<Float> t1(nChan); t1 = 0.0;
734        Vector<Bool> t2(nChan); t2 = True;
735        MaskedArray<Float> vecSum(t1,t2);
736        Float varSum = 0.0;
737        {
738           ReadOnlyVectorIterator<Float> itDataVec(itDataPlane.array(), 1);
739           ReadOnlyVectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
740           while (!itDataVec.pastEnd()) {     
741
742// Create MA of data & mask (optionally including OTF mask) and  get variance
743
744              if (useMask) {
745                 const MaskedArray<Float> spec(itDataVec.vector(),mask&&itMaskVec.vector());
746                 fac = 1.0 / variance(spec);
747              } else {
748                 const MaskedArray<Float> spec(itDataVec.vector(),itMaskVec.vector());
749                 fac = 1.0 / variance(spec);
750              }
751
752// Normalize spectrum (without OTF mask) and accumulate
753
754              const MaskedArray<Float> spec(fac*itDataVec.vector(), itMaskVec.vector());
755              vecSum += spec;
756              varSum += fac;
757
758// Next
759
760              itDataVec.next();
761              itMaskVec.next();
762           }
763        }
764
765// Normalize summed spectrum
766
767        vecSum /= varSum;
768
769// FInd position in input data array.  We are iterating by pol-channel
770// plane so all that will change is beam and IF and that's what we want.
771
772        IPosition pos = itDataPlane.pos();
773
774// Write out data. This is a bit messy. We have to reform the Vector
775// accumulator into an Array of shape (1,1,1,nChan)
776
777        start = pos;
778        end = pos;
779        end(asap::ChanAxis) = nChan-1;
780        outData(start,end) = vecSum.getArray().reform(vecShapeOut);
781        outMask(start,end) = vecSum.getMask().reform(vecShapeOut);
782
783// Step to next beam/IF combination
784
785        itDataPlane.next();
786        itMaskPlane.next();
787      }
788
789// Generate output container and write it to output table
790
791      SDContainer sc = in.getSDContainer();
792      sc.resize(shapeOut);
793//
794      putDataInSDC(sc, outData, outMask);
795      pTabOut->putSDContainer(sc);
796   }
797//
798  return pTabOut;
799}
800
801
802SDMemTable* SDMath::smooth(const SDMemTable& in,
803                           const casa::String& kernelType,
804                           casa::Float width, Bool doAll) const
805{
806
807// Number of channels
808
809   const uInt chanAxis = asap::ChanAxis;  // Spectral axis
810   SDHeader sh = in.getSDHeader();
811   const uInt nChan = sh.nchan;
812
813// Generate Kernel
814
815   VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernelType);
816   Vector<Float> kernel = VectorKernel::make(type, width, nChan, True, False);
817
818// Generate Convolver
819
820   IPosition shape(1,nChan);
821   Convolver<Float> conv(kernel, shape);
822
823// New Table
824
825   SDMemTable* pTabOut = new SDMemTable(in,True);
826
827// Get cursor location
828         
829  IPosition start, end;
830  getCursorLocation(start, end, in);
831//
832  IPosition shapeOut(4,1);
833
834// Output Vectors
835
836  Vector<Float> valuesOut(nChan);
837  Vector<Bool> maskOut(nChan);
838
839// Loop over rows in Table
840
841  for (uInt ri=0; ri < in.nRow(); ++ri) {
842
843// Get copy of data
844   
845    const MaskedArray<Float>& dataIn(in.rowAsMaskedArray(ri));
846    AlwaysAssert(dataIn.shape()(asap::ChanAxis)==nChan, AipsError);
847//
848    Array<Float> valuesIn = dataIn.getArray();
849    Array<Bool> maskIn = dataIn.getMask();
850
851// Branch depending on whether we smooth all locations or just
852// those pointed at by the current selection cursor
853
854    if (doAll) {
855       uInt axis = asap::ChanAxis;
856       VectorIterator<Float> itValues(valuesIn, axis);
857       VectorIterator<Bool> itMask(maskIn, axis);
858       while (!itValues.pastEnd()) {
859
860// Smooth
861          if (kernelType==VectorKernel::HANNING) {
862             mathutil::hanning(valuesOut, maskOut, itValues.vector(), itMask.vector());
863             itMask.vector() = maskOut;
864          } else {
865             mathutil::replaceMaskByZero(itValues.vector(), itMask.vector());
866             conv.linearConv(valuesOut, itValues.vector());
867          }
868//
869          itValues.vector() = valuesOut;
870//
871          itValues.next();
872          itMask.next();
873       }
874    } else {
875
876// Set multi-dim Vector shape
877
878       shapeOut(asap::ChanAxis) = valuesIn.shape()(chanAxis);
879
880// Stuff about with shapes so that we don't have conformance run-time errors
881
882       Vector<Float> valuesIn2 = valuesIn(start,end).nonDegenerate();
883       Vector<Bool> maskIn2 = maskIn(start,end).nonDegenerate();
884
885// Smooth
886
887       if (kernelType==VectorKernel::HANNING) {
888          mathutil::hanning(valuesOut, maskOut, valuesIn2, maskIn2);
889          maskIn(start,end) = maskOut.reform(shapeOut);
890       } else {
891          mathutil::replaceMaskByZero(valuesIn2, maskIn2);
892          conv.linearConv(valuesOut, valuesIn2);
893       }
894//
895       valuesIn(start,end) = valuesOut.reform(shapeOut);
896    }
897
898// Create and put back
899
900    SDContainer sc = in.getSDContainer(ri);
901    putDataInSDC(sc, valuesIn, maskIn);
902//
903    pTabOut->putSDContainer(sc);
904  }
905//
906  return pTabOut;
907}
908
909
910
911SDMemTable* SDMath::convertFlux (const SDMemTable& in, Float a, Float eta, Bool doAll) const
912//
913// As it is, this function could be implemented with 'simpleOperate'
914// However, I anticipate that eventually we will look the conversion
915// values up in a Table and apply them in a frequency dependent way,
916// so I have implemented it fully here
917//
918{
919  SDHeader sh = in.getSDHeader();
920  SDMemTable* pTabOut = new SDMemTable(in, True);
921
922// FInd out how to convert values into Jy and K (e.g. units might be mJy or mK)
923// Also automatically find out what we are converting to according to the
924// flux unit
925
926  Unit fluxUnit(sh.fluxunit);
927  Unit K(String("K"));
928  Unit JY(String("Jy"));
929//
930  Bool toKelvin = True;
931  Double inFac = 1.0;
932  if (fluxUnit==JY) {
933     cerr << "Converting to K" << endl;
934//
935     Quantum<Double> t(1.0,fluxUnit);
936     Quantum<Double> t2 = t.get(JY);
937     inFac = (t2 / t).getValue();
938//
939     toKelvin = True;
940     sh.fluxunit = "K";
941  } else if (fluxUnit==K) {
942     cerr << "Converting to Jy" << endl;
943//
944     Quantum<Double> t(1.0,fluxUnit);
945     Quantum<Double> t2 = t.get(K);
946     inFac = (t2 / t).getValue();
947//
948     toKelvin = False;
949     sh.fluxunit = "Jy";
950  } else {
951     throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
952  }
953  pTabOut->putSDHeader(sh);
954
955// Compute conversion factor. 'a' and 'eta' are really frequency, time and 
956// telescope dependent and should be looked// up in a table
957
958  Float factor = 2.0 * inFac * 1.0e-7 * 1.0e26 *
959                 QC::k.getValue(Unit(String("erg/K"))) / a / eta;
960  if (toKelvin) {
961    factor = 1.0 / factor;
962  }
963  cerr << "Applying conversion factor = " << factor << endl;
964
965// Generate correction vector.  Apply same factor regardless
966// of beam/pol/IF.  This will need to change somewhen.
967
968  Vector<Float> factors(in.nRow(), factor);
969
970// Correct
971
972  correctFromVector (pTabOut, in, doAll, factors);
973//
974  return pTabOut;
975}
976
977
978SDMemTable* SDMath::gainElevation (const SDMemTable& in, const Vector<Float>& coeffs,
979                                   const String& fileName,
980                                   const String& methodStr, Bool doAll) const
981{
982
983// Get header and clone output table
984
985  SDHeader sh = in.getSDHeader();
986  SDMemTable* pTabOut = new SDMemTable(in, True);
987
988// Get elevation data from SDMemTable and convert to degrees
989
990  const Table& tab = in.table();
991  ROScalarColumn<Float> elev(tab, "ELEVATION");
992  Vector<Float> x = elev.getColumn();
993  x *= Float(180 / C::pi);
994//
995  const uInt nC = coeffs.nelements();
996  if (fileName.length()>0 && nC>0) {
997     throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
998  }
999
1000// Correct
1001
1002  if (nC>0 || fileName.length()==0) {
1003
1004// Find instrument
1005
1006     Bool throwIt = True;
1007     Instrument inst = SDMemTable::convertInstrument (sh.antennaname, throwIt);
1008     
1009// Set polynomial
1010
1011     Polynomial<Float>* pPoly = 0;
1012     Vector<Float> coeff;
1013     String msg;
1014     if (nC>0) {
1015        pPoly = new Polynomial<Float>(nC);
1016        coeff = coeffs;
1017        msg = String("user");
1018     } else {
1019        if (inst==PKSMULTIBEAM) {
1020        } else if (inst==PKSSINGLEBEAM) {
1021        } else if (inst==TIDBINBILLA) {
1022           pPoly = new Polynomial<Float>(3);
1023           coeff.resize(3);
1024           coeff(0) = 3.58788e-1;
1025           coeff(1) = 2.87243e-2;
1026           coeff(2) = -3.219093e-4;
1027        } else if (inst==MOPRA) {
1028        }
1029        msg = String("built in");
1030     }
1031//
1032     if (coeff.nelements()>0) {
1033        pPoly->setCoefficients(coeff);
1034     } else {
1035        throw(AipsError("There is no known gain-el polynomial known for this instrument"));
1036     }
1037//
1038     cerr << "Making polynomial correction with " << msg << " coefficients" << endl;
1039     const uInt nRow = in.nRow();
1040     Vector<Float> factor(nRow);
1041     for (uInt i=0; i<nRow; i++) {
1042        factor[i] = (*pPoly)(x[i]);
1043     }
1044     delete pPoly;
1045//
1046     correctFromVector (pTabOut, in, doAll, factor);
1047  } else {
1048
1049// Indicate which columns to read from ascii file
1050
1051     String col0("ELEVATION");
1052     String col1("FACTOR");
1053
1054// Read and correct
1055
1056     cerr << "Making correction from ascii Table" << endl;
1057     correctFromAsciiTable (pTabOut, in, fileName, col0, col1,
1058                            methodStr, doAll, x);
1059   }
1060//
1061   return pTabOut;
1062}
1063
1064 
1065
1066SDMemTable* SDMath::opacity (const SDMemTable& in, Float tau, Bool doAll) const
1067{
1068
1069// Get header and clone output table
1070
1071  SDHeader sh = in.getSDHeader();
1072  SDMemTable* pTabOut = new SDMemTable(in, True);
1073
1074// Get elevation data from SDMemTable and convert to degrees
1075
1076  const Table& tab = in.table();
1077  ROScalarColumn<Float> elev(tab, "ELEVATION");
1078  Vector<Float> zDist = elev.getColumn();
1079  zDist = Float(C::pi_2) - zDist;
1080
1081// Generate correction factor
1082
1083  const uInt nRow = in.nRow();
1084  Vector<Float> factor(nRow);
1085  Vector<Float> factor2(nRow);
1086  for (uInt i=0; i<nRow; i++) {
1087     factor[i] = exp(tau)/cos(zDist[i]);
1088  }
1089
1090// Correct
1091
1092  correctFromVector (pTabOut, in, doAll, factor);
1093//
1094  return pTabOut;
1095}
1096
1097
1098
1099
1100// 'private' functions
1101
1102SDMemTable* SDMath::velocityAlign (const SDMemTable& in,
1103                                   MFrequency::Types velSystem,
1104                                   const String& velUnit,
1105                                   MDoppler::Types doppler) const
1106{
1107// Get Header
1108
1109   SDHeader sh = in.getSDHeader();
1110   const uInt nChan = sh.nchan;
1111   const uInt nRows = in.nRow();
1112
1113// Get Table reference
1114
1115   const Table& tabIn = in.table();
1116
1117// Get Columns from Table
1118
1119  ROScalarColumn<Double> mjdCol(tabIn, "TIME");
1120  ROScalarColumn<String> srcCol(tabIn, "SRCNAME");
1121  ROArrayColumn<uInt> fqIDCol(tabIn, "FREQID");
1122//
1123  Vector<Double> times = mjdCol.getColumn();
1124  Vector<String> srcNames = srcCol.getColumn();
1125  Vector<uInt> freqID;
1126
1127// Generate Source table
1128
1129   Vector<String> srcTab;
1130   Vector<uInt> srcIdx, firstRow;
1131   generateSourceTable (srcTab, srcIdx, firstRow, srcNames);
1132   const uInt nSrcTab = srcTab.nelements();
1133   cerr << "Found " << srcTab.nelements() << " sources to align " << endl;
1134/*
1135   cerr << "source table = " << srcTab << endl;
1136   cerr << "source idx = " << srcIdx << endl;
1137   cerr << "first row = " << firstRow << endl;
1138*/
1139
1140// Set reference Epoch to time of first row
1141
1142   MEpoch::Ref timeRef = MEpoch::Ref(in.getTimeReference());
1143   Unit DAY(String("d"));
1144   Quantum<Double> tQ(times[0], DAY);
1145   MVEpoch mve(tQ);
1146   MEpoch refTime(mve, timeRef);
1147
1148// Set Reference Position
1149
1150   Vector<Double> antPos = sh.antennaposition;
1151   MVPosition mvpos(antPos[0], antPos[1], antPos[2]);
1152   MPosition refPos(mvpos);
1153
1154// Get Frequency Table
1155
1156   SDFrequencyTable fTab = in.getSDFreqTable();
1157   const uInt nFreqIDs = fTab.length();
1158
1159// Create VelocityAligner Block. One VA for each possible
1160// source/freqID combination
1161
1162   PtrBlock<VelocityAligner<Float>* > vA(nFreqIDs*nSrcTab);
1163   for (uInt fqID=0; fqID<nFreqIDs; fqID++) {
1164      SpectralCoordinate sC = in.getCoordinate(fqID);
1165      for (uInt iSrc=0; iSrc<nSrcTab; iSrc++) {
1166         MDirection refDir = in.getDirection(firstRow[iSrc]);
1167         uInt idx = (iSrc*nFreqIDs) + fqID;
1168         vA[idx] = new VelocityAligner<Float>(sC, nChan, refTime, refDir, refPos,
1169                                              velUnit, doppler, velSystem);
1170      }
1171   }
1172
1173// New output Table
1174
1175   SDMemTable* pTabOut = new SDMemTable(in,True);
1176
1177// Loop over rows in Table
1178
1179  const IPosition polChanAxes(2, asap::PolAxis, asap::ChanAxis);
1180  VelocityAligner<Float>::Method method = VelocityAligner<Float>::LINEAR;
1181  Bool extrapolate=False;
1182  Bool useCachedAbcissa = False;
1183  Bool first = True;
1184  Bool ok;
1185  Vector<Float> yOut;
1186  Vector<Bool> maskOut;
1187  uInt ifIdx, vaIdx;
1188//
1189  for (uInt iRow=0; iRow<nRows; ++iRow) {
1190     if (iRow%10==0) {
1191        cerr << "Processing row " << iRow << endl;
1192     }
1193
1194// Get EPoch
1195
1196    Quantum<Double> tQ2(times[iRow],DAY);
1197    MVEpoch mv2(tQ2);
1198    MEpoch epoch(mv2, timeRef);
1199
1200// Get FreqID vector.  One freqID per IF
1201
1202    fqIDCol.get(iRow, freqID);
1203
1204// Get copy of data
1205   
1206    const MaskedArray<Float>& mArrIn(in.rowAsMaskedArray(iRow));
1207    Array<Float> values = mArrIn.getArray();
1208    Array<Bool> mask = mArrIn.getMask();
1209
1210// cerr << "values in = " << values(IPosition(4,0,0,0,0),IPosition(4,0,0,0,9)) << endl;
1211
1212// For each row, the Velocity abcissa will be the same regardless
1213// of polarization.  For all other axes (IF and BEAM) the abcissa
1214// will change.  So we iterate through the data by pol-chan planes
1215// to mimimize the work.  At this point, I think the Direction
1216// is stored as the same for each beam. DOn't know where the
1217// offsets are or what to do about them right now.  For now
1218// all beams get same position and velocoity abcissa.
1219
1220    ArrayIterator<Float> itValuesPlane(values, polChanAxes);
1221    ArrayIterator<Bool> itMaskPlane(mask, polChanAxes);
1222    while (!itValuesPlane.pastEnd()) {
1223
1224// Find the IF index and then the VA PtrBlock index
1225
1226       const IPosition& pos = itValuesPlane.pos();
1227       ifIdx = pos(asap::IFAxis);
1228       vaIdx = (srcIdx[iRow]*nFreqIDs) + freqID[ifIdx];
1229//
1230       VectorIterator<Float> itValuesVec(itValuesPlane.array(), 1);
1231       VectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
1232//
1233       first = True;
1234       useCachedAbcissa=False;
1235       while (!itValuesVec.pastEnd()) {     
1236          ok = vA[vaIdx]->align (yOut, maskOut, itValuesVec.vector(),
1237                                 itMaskVec.vector(), epoch, useCachedAbcissa,
1238                                 method, extrapolate);
1239          itValuesVec.vector() = yOut;
1240          itMaskVec.vector() = maskOut;
1241//
1242          itValuesVec.next();
1243          itMaskVec.next();
1244//
1245          if (first) {
1246             useCachedAbcissa = True;
1247             first = False;
1248          }
1249       }
1250//
1251       itValuesPlane.next();
1252       itMaskPlane.next();
1253    }
1254
1255// cerr << "values out = " << values(IPosition(4,0,0,0,0),IPosition(4,0,0,0,9)) << endl;
1256
1257// Create and put back
1258
1259    SDContainer sc = in.getSDContainer(iRow);
1260    putDataInSDC(sc, values, mask);
1261//
1262    pTabOut->putSDContainer(sc);
1263  }
1264
1265// Clean up PointerBlock
1266
1267  for (uInt i=0; i<vA.nelements(); i++) delete vA[i];
1268//
1269  return pTabOut;
1270}
1271
1272
1273void SDMath::fillSDC(SDContainer& sc,
1274                     const Array<Bool>& mask,
1275                     const Array<Float>& data,
1276                     const Array<Float>& tSys,
1277                     Int scanID, Double timeStamp,
1278                     Double interval, const String& sourceName,
1279                     const Vector<uInt>& freqID) const
1280{
1281// Data and mask
1282
1283  putDataInSDC(sc, data, mask);
1284
1285// TSys
1286
1287  sc.putTsys(tSys);
1288
1289// Time things
1290
1291  sc.timestamp = timeStamp;
1292  sc.interval = interval;
1293  sc.scanid = scanID;
1294//
1295  sc.sourcename = sourceName;
1296  sc.putFreqMap(freqID);
1297}
1298
1299void SDMath::normalize(MaskedArray<Float>& sum,
1300                        const Array<Float>& sumSq,
1301                        const Array<Float>& nPts,
1302                        WeightType wtType, Int axis,
1303                        Int nAxesSub) const
1304{
1305   IPosition pos2(nAxesSub,0);
1306//
1307   if (wtType==NONE) {
1308
1309// We just average by the number of points accumulated.
1310// We need to make a MA out of nPts so that no divide by
1311// zeros occur
1312
1313      MaskedArray<Float> t(nPts, (nPts>Float(0.0)));
1314      sum /= t;
1315   } else if (wtType==VAR) {
1316
1317// Normalize each spectrum by sum(1/var) where the variance
1318// is worked out for each spectrum
1319
1320      Array<Float>& data = sum.getRWArray();
1321      VectorIterator<Float> itData(data, axis);
1322      while (!itData.pastEnd()) {
1323         pos2 = itData.pos().getFirst(nAxesSub);
1324         itData.vector() /= sumSq(pos2);
1325         itData.next();
1326      }
1327   } else if (wtType==TSYS) {
1328   }
1329}
1330
1331
1332void SDMath::accumulate(Double& timeSum, Double& intSum, Int& nAccum,
1333                        MaskedArray<Float>& sum, Array<Float>& sumSq,
1334                        Array<Float>& nPts, Array<Float>& tSysSum,
1335                        const Array<Float>& tSys, const Array<Float>& nInc,
1336                        const Vector<Bool>& mask, Double time, Double interval,
1337                        const Block<CountedPtr<SDMemTable> >& in,
1338                        uInt iTab, uInt iRow, uInt axis,
1339                        uInt nAxesSub, Bool useMask,
1340                        WeightType wtType) const
1341{
1342
1343// Get data
1344
1345   MaskedArray<Float> dataIn(in[iTab]->rowAsMaskedArray(iRow));
1346   Array<Float>& valuesIn = dataIn.getRWArray();           // writable reference
1347   const Array<Bool>& maskIn = dataIn.getMask();          // RO reference
1348//
1349   if (wtType==NONE) {
1350      const MaskedArray<Float> n(nInc,dataIn.getMask());
1351      nPts += n;                               // Only accumulates where mask==T
1352   } else if (wtType==VAR) {
1353
1354// We are going to average the data, weighted by the noise for each pol, beam and IF.
1355// So therefore we need to iterate through by spectrum (axis 3)
1356
1357      VectorIterator<Float> itData(valuesIn, axis);
1358      ReadOnlyVectorIterator<Bool> itMask(maskIn, axis);
1359      Float fac = 1.0;
1360      IPosition pos(nAxesSub,0); 
1361//
1362      while (!itData.pastEnd()) {
1363
1364// Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor
1365
1366        if (useMask) {
1367           MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());
1368           fac = 1.0/variance(tmp);
1369        } else {
1370           MaskedArray<Float> tmp(itData.vector(),itMask.vector());
1371           fac = 1.0/variance(tmp);
1372        }
1373
1374// Scale data
1375
1376        itData.vector() *= fac;     // Writes back into 'dataIn'
1377//
1378// Accumulate variance per if/pol/beam averaged over spectrum
1379// This method to get pos2 from itData.pos() is only valid
1380// because the spectral axis is the last one (so we can just
1381// copy the first nAXesSub positions out)
1382
1383        pos = itData.pos().getFirst(nAxesSub);
1384        sumSq(pos) += fac;
1385//
1386        itData.next();
1387        itMask.next();
1388      }
1389   } else if (wtType==TSYS) {
1390   }
1391
1392// Accumulate sum of (possibly scaled) data
1393
1394   sum += dataIn;
1395
1396// Accumulate Tsys, time, and interval
1397
1398   tSysSum += tSys;
1399   timeSum += time;
1400   intSum += interval;
1401   nAccum += 1;
1402}
1403
1404
1405
1406
1407void SDMath::getCursorLocation(IPosition& start, IPosition& end,
1408                               const SDMemTable& in) const
1409{
1410  const uInt nDim = 4;
1411  const uInt i = in.getBeam();
1412  const uInt j = in.getIF();
1413  const uInt k = in.getPol();
1414  const uInt n = in.nChan();
1415//
1416  start.resize(nDim);
1417  start(0) = i;
1418  start(1) = j;
1419  start(2) = k;
1420  start(3) = 0;
1421//
1422  end.resize(nDim);
1423  end(0) = i;
1424  end(1) = j;
1425  end(2) = k;
1426  end(3) = n-1;
1427}
1428
1429
1430void SDMath::convertWeightString(WeightType& wtType, const String& weightStr) const
1431{
1432  String tStr(weightStr);
1433  tStr.upcase();
1434  if (tStr.contains(String("NONE"))) {
1435     wtType = NONE;
1436  } else if (tStr.contains(String("VAR"))) {
1437     wtType = VAR;
1438  } else if (tStr.contains(String("TSYS"))) {
1439     wtType = TSYS;
1440     throw(AipsError("T_sys weighting not yet implemented"));
1441  } else {
1442    throw(AipsError("Unrecognized weighting type"));
1443  }
1444}
1445
1446void SDMath::convertInterpString(Int& type, const String& interp) const
1447{
1448  String tStr(interp);
1449  tStr.upcase();
1450  if (tStr.contains(String("NEAR"))) {
1451     type = InterpolateArray1D<Float,Float>::nearestNeighbour;
1452  } else if (tStr.contains(String("LIN"))) {
1453     type = InterpolateArray1D<Float,Float>::linear;
1454  } else if (tStr.contains(String("CUB"))) {
1455     type = InterpolateArray1D<Float,Float>::cubic;
1456  } else if (tStr.contains(String("SPL"))) {
1457     type = InterpolateArray1D<Float,Float>::spline;
1458  } else {
1459    throw(AipsError("Unrecognized interpolation type"));
1460  }
1461}
1462
1463void SDMath::putDataInSDC(SDContainer& sc, const Array<Float>& data,
1464                          const Array<Bool>& mask) const
1465{
1466    sc.putSpectrum(data);
1467//
1468    Array<uChar> outflags(data.shape());
1469    convertArray(outflags,!mask);
1470    sc.putFlags(outflags);
1471}
1472
1473Table SDMath::readAsciiFile (const String& fileName) const
1474{
1475   String formatString;
1476   Table tbl = readAsciiTable (formatString, Table::Memory, fileName, "", "", False);
1477   return tbl;
1478}
1479
1480
1481
1482void SDMath::correctFromAsciiTable(SDMemTable* pTabOut,
1483                                   const SDMemTable& in, const String& fileName,
1484                                   const String& col0, const String& col1,
1485                                   const String& methodStr, Bool doAll,
1486                                   const Vector<Float>& xOut) const
1487{
1488
1489// Read gain-elevation ascii file data into a Table.
1490
1491  Table geTable = readAsciiFile (fileName);
1492//
1493  correctFromTable (pTabOut, in, geTable, col0, col1, methodStr, doAll, xOut);
1494}
1495
1496void SDMath::correctFromTable(SDMemTable* pTabOut, const SDMemTable& in,
1497                              const Table& tTable, const String& col0,
1498                              const String& col1,
1499                              const String& methodStr, Bool doAll,
1500                              const Vector<Float>& xOut) const
1501{
1502
1503// Get data from Table
1504
1505  ROScalarColumn<Float> geElCol(tTable, col0);
1506  ROScalarColumn<Float> geFacCol(tTable, col1);
1507  Vector<Float> xIn = geElCol.getColumn();
1508  Vector<Float> yIn = geFacCol.getColumn();
1509  Vector<Bool> maskIn(xIn.nelements(),True);
1510
1511// Interpolate (and extrapolate) with desired method
1512
1513   Int method = 0;
1514   convertInterpString(method, methodStr);
1515//
1516   Vector<Float> yOut;
1517   Vector<Bool> maskOut;
1518   InterpolateArray1D<Float,Float>::interpolate(yOut, maskOut, xOut,
1519                                                xIn, yIn, maskIn, method,
1520                                                True, True);
1521// Apply
1522
1523   correctFromVector (pTabOut, in, doAll, yOut);
1524}
1525
1526
1527void SDMath::correctFromVector (SDMemTable* pTabOut, const SDMemTable& in,
1528                                Bool doAll, const Vector<Float>& factor) const
1529{
1530
1531// For operations only on specified cursor location
1532
1533  IPosition start, end;
1534  getCursorLocation(start, end, in);
1535
1536// Loop over rows and apply correction factor
1537 
1538  const uInt axis = asap::ChanAxis;
1539  for (uInt i=0; i < in.nRow(); ++i) {
1540
1541// Get data
1542
1543    MaskedArray<Float> dataIn(in.rowAsMaskedArray(i));
1544
1545// Apply factor
1546
1547    if (doAll) {
1548       dataIn *= factor[i];
1549    } else {
1550       MaskedArray<Float> dataIn2 = dataIn(start,end);  // reference
1551       dataIn2 *= factor[i];
1552    }
1553
1554// Write out
1555
1556    SDContainer sc = in.getSDContainer(i);
1557    putDataInSDC(sc, dataIn.getArray(), dataIn.getMask());
1558//
1559    pTabOut->putSDContainer(sc);
1560  }
1561}
1562
1563
1564void SDMath::generateSourceTable (Vector<String>& srcTab,
1565                                  Vector<uInt>& srcIdx,
1566                                  Vector<uInt>& firstRow,
1567                                  const Vector<String>& srcNames) const
1568//
1569// This algorithm assumes that if there are multiple beams
1570// that the source names are diffent.  Oterwise we would need
1571// to look atthe direction for each beam...
1572//
1573{
1574   const uInt nRow = srcNames.nelements();
1575   srcTab.resize(0);
1576   srcIdx.resize(nRow);
1577   firstRow.resize(0);
1578//
1579   uInt nSrc = 0;
1580   for (uInt i=0; i<nRow; i++) {
1581      String srcName = srcNames[i];
1582     
1583// Do we have this source already ?
1584
1585      Int idx = -1;
1586      if (nSrc>0) {
1587         for (uInt j=0; j<nSrc; j++) {
1588           if (srcName==srcTab[j]) {
1589              idx = j;
1590              break;
1591           }
1592         }
1593      }
1594
1595// Add new entry if not found
1596
1597      if (idx==-1) {
1598         nSrc++;
1599         srcTab.resize(nSrc,True);
1600         srcTab(nSrc-1) = srcName;
1601         idx = nSrc-1;
1602//
1603         firstRow.resize(nSrc,True);
1604         firstRow(nSrc-1) = i;       // First row for which this source occurs
1605      }
1606
1607// Set index for this row
1608
1609      srcIdx[i] = idx;
1610   }
1611}
Note: See TracBrowser for help on using the repository browser.