source: trunk/src/SDMath.cc @ 165

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

Reimplement 'average_pol' with both insitu and 'outsit' versions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.2 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/Exceptions.h>
45
46#include <tables/Tables/Table.h>
47#include <tables/Tables/ScalarColumn.h>
48#include <tables/Tables/ArrayColumn.h>
49
50#include <lattices/Lattices/LatticeUtilities.h>
51#include <lattices/Lattices/RebinLattice.h>
52#include <coordinates/Coordinates/SpectralCoordinate.h>
53#include <coordinates/Coordinates/CoordinateSystem.h>
54#include <coordinates/Coordinates/CoordinateUtil.h>
55
56#include "MathUtils.h"
57#include "SDContainer.h"
58#include "SDMemTable.h"
59
60#include "SDMath.h"
61
62using namespace casa;
63using namespace asap;
64
65CountedPtr<SDMemTable> SDMath::average (const Block<CountedPtr<SDMemTable> >& in,
66                                        const Vector<Bool>& mask, bool scanAv,
67                                        const std::string& weightStr)
68//
69// Weighted averaging of spectra from one or more Tables.
70//
71{
72
73// Convert weight type
74 
75  WeightType wtType = NONE;
76  convertWeightString (wtType, weightStr);
77
78// Create output Table by cloning from the first table
79
80  SDMemTable* pTabOut = new SDMemTable(*in[0],True);
81
82// Setup
83
84  const uInt axis = 3;                                     // Spectral axis
85  IPosition shp = in[0]->rowAsMaskedArray(0).shape();      // Must not change
86  Array<Float> arr(shp);
87  Array<Bool> barr(shp);
88  const Bool useMask = (mask.nelements() == shp(axis));
89
90// Columns from Tables
91
92  ROArrayColumn<Float> tSysCol;
93  ROScalarColumn<Double> mjdCol;
94  ROScalarColumn<String> srcNameCol;
95  ROScalarColumn<Double> intCol;
96  ROArrayColumn<uInt> fqIDCol;
97
98// Create accumulation MaskedArray. We accumulate for each channel,if,pol,beam
99// Note that the mask of the accumulation array will ALWAYS remain ALL True.
100// The MA is only used so that when data which is masked Bad is added to it,
101// that data does not contribute.
102
103  Array<Float> zero(shp);
104  zero=0.0;
105  Array<Bool> good(shp);
106  good = True;
107  MaskedArray<Float> sum(zero,good);
108
109// Counter arrays
110
111  Array<Float> nPts(shp);             // Number of points
112  nPts = 0.0;
113  Array<Float> nInc(shp);             // Increment
114  nInc = 1.0;
115
116// Create accumulation Array for variance. We accumulate for
117// each if,pol,beam, but average over channel.  So we need
118// a shape with one less axis dropping channels.
119
120  const uInt nAxesSub = shp.nelements() - 1;
121  IPosition shp2(nAxesSub);
122  for (uInt i=0,j=0; i<(nAxesSub+1); i++) {
123     if (i!=axis) {
124       shp2(j) = shp(i);
125       j++;
126     }
127  }
128  Array<Float> sumSq(shp2);
129  sumSq = 0.0;
130  IPosition pos2(nAxesSub,0);                        // For indexing
131
132// Time-related accumulators
133
134  Double time;
135  Double timeSum = 0.0;
136  Double intSum = 0.0;
137  Double interval = 0.0;
138
139// To get the right shape for the Tsys accumulator we need to
140// access a column from the first table.  The shape of this
141// array must not change
142
143  Array<Float> tSysSum;
144  {
145    const Table& tabIn = in[0]->table();
146    tSysCol.attach(tabIn,"TSYS");
147    tSysSum.resize(tSysCol.shape(0));
148  }
149  tSysSum =0.0;
150  Array<Float> tSys;
151
152// Scan and row tracking
153
154  Int oldScanID = 0;
155  Int outScanID = 0;
156  Int scanID = 0;
157  Int rowStart = 0;
158  Int nAccum = 0;
159  Int tableStart = 0;
160
161// Source and FreqID
162
163  String sourceName, oldSourceName, sourceNameStart;
164  Vector<uInt> freqID, freqIDStart, oldFreqID;
165
166// Loop over tables
167
168  Float fac = 1.0;
169  const uInt nTables = in.nelements();
170  for (uInt iTab=0; iTab<nTables; iTab++) {
171
172// Attach columns to Table
173
174     const Table& tabIn = in[iTab]->table();
175     tSysCol.attach(tabIn, "TSYS");
176     mjdCol.attach(tabIn, "TIME");
177     srcNameCol.attach(tabIn, "SRCNAME");
178     intCol.attach(tabIn, "INTERVAL");
179     fqIDCol.attach(tabIn, "FREQID");
180
181// Loop over rows in Table
182
183     const uInt nRows = in[iTab]->nRow();
184     for (uInt iRow=0; iRow<nRows; iRow++) {
185
186// Check conformance
187
188        IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();
189        if (!shp.isEqual(shp2)) {
190           throw (AipsError("Shapes for all rows must be the same"));
191        }
192
193// If we are not doing scan averages, make checks for source and
194// frequency setup and warn if averaging across them
195
196// Get copy of Scan Container for this row
197
198        SDContainer sc = in[iTab]->getSDContainer(iRow);
199        scanID = sc.scanid;
200
201// Get quantities from columns
202
203        srcNameCol.getScalar(iRow, sourceName);
204        mjdCol.get(iRow, time);
205        tSysCol.get(iRow, tSys);
206        intCol.get(iRow, interval);
207        fqIDCol.get(iRow, freqID);
208
209// Initialize first source and freqID
210
211        if (iRow==0 && iTab==0) {
212          sourceNameStart = sourceName;
213          freqIDStart = freqID;
214        }
215
216// If we are doing scan averages, see if we are at the end of an
217// accumulation period (scan).  We must check soutce names too,
218// since we might have two tables with one scan each but different
219// source names; we shouldn't average different sources together
220
221        if (scanAv && ( (scanID != oldScanID)  ||
222                        (iRow==0 && iTab>0 && sourceName!=oldSourceName))) {
223
224// Normalize data in 'sum' accumulation array according to weighting scheme
225
226           normalize (sum, sumSq, nPts, wtType, axis, nAxesSub);
227
228// Fill scan container. The source and freqID come from the
229// first row of the first table that went into this average (
230// should be the same for all rows in the scan average)
231
232           Float nR(nAccum);
233           fillSDC (sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
234                    timeSum/nR, intSum, sourceNameStart, freqIDStart);
235
236// Write container out to Table
237
238           pTabOut->putSDContainer(sc);
239
240// Reset accumulators
241
242           sum = 0.0;
243           sumSq = 0.0;
244           nAccum = 0;
245//
246           tSysSum =0.0;
247           timeSum = 0.0;
248           intSum = 0.0;
249
250// Increment
251
252           rowStart = iRow;              // First row for next accumulation
253           tableStart = iTab;            // First table for next accumulation
254           sourceNameStart = sourceName; // First source name for next accumulation
255           freqIDStart = freqID;         // First FreqID for next accumulation
256//
257           oldScanID = scanID;
258           outScanID += 1;               // Scan ID for next accumulation period
259        }
260
261// Accumulate
262
263        accumulate (timeSum, intSum, nAccum, sum, sumSq, nPts, tSysSum,
264                    tSys, nInc, mask, time, interval, in, iTab, iRow, axis,
265                    nAxesSub, useMask, wtType);
266//
267       oldSourceName = sourceName;
268       oldFreqID = freqID;
269    }
270  }
271
272// OK at this point we have accumulation data which is either
273//   - accumulated from all tables into one row
274// or
275//   - accumulated from the last scan average
276//
277// Normalize data in 'sum' accumulation array according to weighting scheme
278
279  normalize (sum, sumSq, nPts, wtType, axis, nAxesSub);
280
281// Create and fill container.  The container we clone will be from
282// the last Table and the first row that went into the current
283// accumulation.  It probably doesn't matter that much really...
284
285  Float nR(nAccum);
286  SDContainer sc = in[tableStart]->getSDContainer(rowStart);
287  fillSDC (sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
288           timeSum/nR, intSum, sourceNameStart, freqIDStart);
289//
290  pTabOut->putSDContainer(sc);
291/*
292   cout << endl;
293   cout << "Last accumulation for output scan ID " << outScanID << endl;
294   cout << "   The first row in this accumulation is " << rowStart << endl;
295   cout << "   The number of rows accumulated is " << nAccum << endl;
296   cout << "   The first table in this accumulation is " << tableStart << endl;
297   cout << "   The first source in this accumulation is " << sourceNameStart << endl;
298   cout << "   The first freqID in this accumulation is " << freqIDStart << endl;
299   cout  << "   Average time stamp = " << timeSum/nR << endl;
300   cout << "   Integrated time = " << intSum << endl;
301*/
302  return CountedPtr<SDMemTable>(pTabOut);
303}
304
305
306
307CountedPtr<SDMemTable>
308SDMath::quotient(const CountedPtr<SDMemTable>& on,
309                 const CountedPtr<SDMemTable>& off)
310//
311// Compute quotient spectrum
312//
313{
314  const uInt nRows = on->nRow();
315  if (off->nRow() != nRows) {
316     throw (AipsError("Input Scan Tables must have the same number of rows"));
317  }
318
319// Input Tables and columns
320
321  Table ton = on->table();
322  Table toff = off->table();
323  ROArrayColumn<Float> tsys(toff, "TSYS");
324  ROScalarColumn<Double> mjd(ton, "TIME");
325  ROScalarColumn<Double> integr(ton, "INTERVAL");
326  ROScalarColumn<String> srcn(ton, "SRCNAME");
327  ROArrayColumn<uInt> freqidc(ton, "FREQID");
328
329// Output Table cloned from input
330
331  SDMemTable* sdmt = new SDMemTable(*on, True);
332
333// Loop over rows
334
335  for (uInt i=0; i<nRows; i++) {
336     MaskedArray<Float> mon(on->rowAsMaskedArray(i));
337     MaskedArray<Float> moff(off->rowAsMaskedArray(i));
338     IPosition ipon = mon.shape();
339     IPosition ipoff = moff.shape();
340//
341     Array<Float> tsarr; 
342     tsys.get(i, tsarr);
343     if (ipon != ipoff && ipon != tsarr.shape()) {
344       throw(AipsError("on/off not conformant"));
345     }
346
347// Compute quotient
348
349     MaskedArray<Float> tmp = (mon-moff);
350     Array<Float> out(tmp.getArray());
351     out /= moff;
352     out *= tsarr;
353     Array<Bool> outflagsb = mon.getMask() && moff.getMask();
354
355// Fill container for this row
356
357     SDContainer sc = on->getSDContainer();
358//
359     putDataInSDC (sc, out, outflagsb);
360     sc.putTsys(tsarr);
361     sc.scanid = 0;
362
363// Put new row in output Table
364
365     sdmt->putSDContainer(sc);
366  }
367//
368  return CountedPtr<SDMemTable>(sdmt);
369}
370
371void SDMath::multiplyInSitu(SDMemTable* pIn, Float factor, Bool doAll)
372{
373  const uInt what = 0;
374  SDMemTable* pOut = localOperate (*pIn, factor, doAll, what);
375  *pIn = *pOut;
376   delete pOut;
377
378
379
380CountedPtr<SDMemTable>
381SDMath::multiply(const CountedPtr<SDMemTable>& in, Float factor, Bool doAll)
382{
383  const uInt what = 0;
384  return CountedPtr<SDMemTable>(localOperate (*in, factor, doAll, what));
385}
386
387
388void SDMath::addInSitu (SDMemTable* pIn, Float offset, Bool doAll)
389{
390  const uInt what = 1;
391  SDMemTable* pOut = localOperate (*pIn, offset, doAll, what);
392  *pIn = *pOut;
393   delete pOut;
394
395
396
397CountedPtr<SDMemTable>
398SDMath::add(const CountedPtr<SDMemTable>& in, Float offset, Bool doAll)
399{
400  const uInt what = 1;
401  return CountedPtr<SDMemTable>(localOperate(*in, offset, doAll, what));
402}
403
404
405CountedPtr<SDMemTable>
406SDMath::hanning(const CountedPtr<SDMemTable>& in)
407//
408// Hanning smooth each row
409// Should Tsys be smoothed ?
410//
411{
412  SDMemTable* sdmt = new SDMemTable(*in,True);
413
414// Loop over rows in Table
415
416  for (uInt ri=0; ri < in->nRow(); ++ri) {
417
418// Get data
419   
420    const MaskedArray<Float>& marr(in->rowAsMaskedArray(ri));
421    Array<Float> arr = marr.getArray();
422    Array<Bool> barr = marr.getMask();
423
424// Smooth along the channels axis
425
426    uInt axis = 3;
427    VectorIterator<Float> itData(arr, axis);
428    VectorIterator<Bool> itMask(barr, axis);
429    Vector<Float> outv;
430    Vector<Bool> outm;
431    while (!itData.pastEnd()) {
432       mathutil::hanning(outv, outm, itData.vector(), itMask.vector());
433       itData.vector() = outv;                                                 
434       itMask.vector() = outm;
435//
436       itData.next();
437       itMask.next();
438    }
439
440// Create and put back
441
442    SDContainer sc = in->getSDContainer(ri);
443    putDataInSDC (sc, arr, barr);
444//
445    sdmt->putSDContainer(sc);
446  }
447  return CountedPtr<SDMemTable>(sdmt);
448}
449
450void SDMath::averagePolInSitu (SDMemTable* pIn, const Vector<Bool>& mask)
451{
452  SDMemTable* pOut = localAveragePol (*pIn, mask);
453  *pIn = *pOut;
454   delete pOut;
455
456
457
458CountedPtr<SDMemTable> SDMath::averagePol (const CountedPtr<SDMemTable>& in,
459                                           const Vector<Bool>& mask)
460{
461  return CountedPtr<SDMemTable>(localAveragePol(*in, mask));
462}
463
464CountedPtr<SDMemTable> SDMath::bin(const CountedPtr<SDMemTable>& in,
465                                   Int width)
466{
467  SDHeader sh = in->getSDHeader();
468  SDMemTable* sdmt = new SDMemTable(*in,True);
469
470// Bin up SpectralCoordinates
471
472  IPosition factors(1);
473  factors(0) = width;
474  for (uInt j=0; j<in->nCoordinates(); ++j) {
475    CoordinateSystem cSys;
476    cSys.addCoordinate(in->getCoordinate(j));
477    CoordinateSystem cSysBin =
478      CoordinateUtil::makeBinnedCoordinateSystem (factors, cSys, False);
479//
480    SpectralCoordinate sCBin = cSysBin.spectralCoordinate(0);
481    sdmt->setCoordinate(sCBin, j);
482  }
483
484// Use RebinLattice to find shape
485
486  IPosition shapeIn(1,sh.nchan);
487  IPosition shapeOut = RebinLattice<Float>::rebinShape (shapeIn, factors);
488  sh.nchan = shapeOut(0);
489  sdmt->putSDHeader(sh);
490
491
492// Loop over rows and bin along channel axis
493 
494  const uInt axis = 3;
495  for (uInt i=0; i < in->nRow(); ++i) {
496    SDContainer sc = in->getSDContainer(i);
497//
498    Array<Float> tSys(sc.getTsys());                           // Get it out before sc changes shape
499
500// Bin up spectrum
501
502    MaskedArray<Float> marr(in->rowAsMaskedArray(i));
503    MaskedArray<Float> marrout;
504    LatticeUtilities::bin(marrout, marr, axis, width);
505
506// Put back the binned data and flags
507
508    IPosition ip2 = marrout.shape();
509    sc.resize(ip2);
510//
511    putDataInSDC (sc, marrout.getArray(), marrout.getMask());
512
513// Bin up Tsys. 
514
515    Array<Bool> allGood(tSys.shape(),True);
516    MaskedArray<Float> tSysIn(tSys, allGood, True);
517//
518    MaskedArray<Float> tSysOut;   
519    LatticeUtilities::bin(tSysOut, tSysIn, axis, width);
520    sc.putTsys(tSysOut.getArray());
521//
522    sdmt->putSDContainer(sc);
523  }
524  return CountedPtr<SDMemTable>(sdmt);
525}
526
527
528
529std::vector<float> SDMath::statistic (const CountedPtr<SDMemTable>& in,
530                                       const std::vector<bool>& mask,
531                                       const std::string& which)
532//
533// Perhaps iteration over pol/beam/if should be in here
534// and inside the nrow iteration ?
535//
536{
537  const uInt nRow = in->nRow();
538  std::vector<float> result(nRow);
539  Vector<Bool> msk(mask);
540
541// Specify cursor location
542
543  IPosition start, end;
544  getCursorLocation (start, end, *in);
545
546// Loop over rows
547
548  const uInt nEl = msk.nelements();
549  for (uInt ii=0; ii < in->nRow(); ++ii) {
550
551// Get row and deconstruct
552
553     MaskedArray<Float> marr(in->rowAsMaskedArray(ii));
554     Array<Float> arr = marr.getArray();
555     Array<Bool> barr = marr.getMask();
556
557// Access desired piece of data
558
559     Array<Float> v((arr(start,end)).nonDegenerate());
560     Array<Bool> m((barr(start,end)).nonDegenerate());
561
562// Apply OTF mask
563
564     MaskedArray<Float> tmp;
565     if (m.nelements()==nEl) {
566       tmp.setData(v,m&&msk);
567     } else {
568       tmp.setData(v,m);
569     }
570
571// Get statistic
572
573     result[ii] = mathutil::statistics(which, tmp);
574  }
575//
576  return result;
577}
578
579
580
581// 'private' functions
582
583void SDMath::fillSDC (SDContainer& sc,
584                      const Array<Bool>& mask,
585                      const Array<Float>& data,
586                      const Array<Float>& tSys,
587                      Int scanID, Double timeStamp,
588                      Double interval, const String& sourceName,
589                      const Vector<uInt>& freqID)
590{
591// Data and mask
592
593  putDataInSDC (sc, data, mask);
594
595// TSys
596
597  sc.putTsys(tSys);
598
599// Time things
600
601  sc.timestamp = timeStamp;
602  sc.interval = interval;
603  sc.scanid = scanID;
604//
605  sc.sourcename = sourceName;
606  sc.putFreqMap(freqID);
607}
608
609void SDMath::normalize (MaskedArray<Float>& sum,
610                        const Array<Float>& sumSq,
611                        const Array<Float>& nPts,
612                        WeightType wtType, Int axis,
613                        Int nAxesSub)
614{
615   IPosition pos2(nAxesSub,0);
616//
617   if (wtType==NONE) {
618
619// We just average by the number of points accumulated.
620// We need to make a MA out of nPts so that no divide by
621// zeros occur
622
623      MaskedArray<Float> t(nPts, (nPts>Float(0.0)));
624      sum /= t;
625   } else if (wtType==VAR) {
626
627// Normalize each spectrum by sum(1/var) where the variance
628// is worked out for each spectrum
629
630      Array<Float>& data = sum.getRWArray();
631      VectorIterator<Float> itData(data, axis);
632      while (!itData.pastEnd()) {
633         pos2 = itData.pos().getFirst(nAxesSub);
634         itData.vector() /= sumSq(pos2);
635         itData.next();
636      }
637   } else if (wtType==TSYS) {
638   }
639}
640
641
642void SDMath::accumulate (Double& timeSum, Double& intSum, Int& nAccum,
643                         MaskedArray<Float>& sum, Array<Float>& sumSq,
644                         Array<Float>& nPts, Array<Float>& tSysSum,
645                         const Array<Float>& tSys, const Array<Float>& nInc,
646                         const Vector<Bool>& mask, Double time, Double interval,
647                         const Block<CountedPtr<SDMemTable> >& in,
648                         uInt iTab, uInt iRow, uInt axis,
649                         uInt nAxesSub, Bool useMask,
650                         WeightType wtType)
651{
652
653// Get data
654
655   MaskedArray<Float> dataIn(in[iTab]->rowAsMaskedArray(iRow));
656   Array<Float>& valuesIn = dataIn.getRWArray();           // writable reference
657   const Array<Bool>& maskIn = dataIn.getMask();          // RO reference
658//
659   if (wtType==NONE) {
660      const MaskedArray<Float> n(nInc,dataIn.getMask());
661      nPts += n;                               // Only accumulates where mask==T
662   } else if (wtType==VAR) {
663
664// We are going to average the data, weighted by the noise for each pol, beam and IF.
665// So therefore we need to iterate through by spectrum (axis 3)
666
667      VectorIterator<Float> itData(valuesIn, axis);
668      ReadOnlyVectorIterator<Bool> itMask(maskIn, axis);
669      Float fac = 1.0;
670      IPosition pos(nAxesSub,0); 
671//
672      while (!itData.pastEnd()) {
673
674// Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor
675
676        if (useMask) {
677           MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());
678           fac = 1.0/variance(tmp);
679        } else {
680           MaskedArray<Float> tmp(itData.vector(),itMask.vector());
681           fac = 1.0/variance(tmp);
682        }
683
684// Scale data
685
686        itData.vector() *= fac;     // Writes back into 'dataIn'
687//
688// Accumulate variance per if/pol/beam averaged over spectrum
689// This method to get pos2 from itData.pos() is only valid
690// because the spectral axis is the last one (so we can just
691// copy the first nAXesSub positions out)
692
693        pos = itData.pos().getFirst(nAxesSub);
694        sumSq(pos) += fac;
695//
696        itData.next();
697        itMask.next();
698      }
699   } else if (wtType==TSYS) {
700   }
701
702// Accumulate sum of (possibly scaled) data
703
704   sum += dataIn;
705
706// Accumulate Tsys, time, and interval
707
708   tSysSum += tSys;
709   timeSum += time;
710   intSum += interval;
711   nAccum += 1;
712}
713
714SDMemTable* SDMath::localOperate (const SDMemTable& in, Float val, Bool doAll,
715                                  uInt what)
716//
717// what = 0   Multiply
718//        1   Add
719{
720   SDMemTable* pOut = new SDMemTable(in,False);
721   const Table& tOut = pOut->table();
722   ArrayColumn<Float> spec(tOut,"SPECTRA"); 
723//
724   if (doAll) {
725      for (uInt i=0; i < tOut.nrow(); i++) {
726
727// Get
728
729         MaskedArray<Float> marr(pOut->rowAsMaskedArray(i));
730
731// Operate
732
733         if (what==0) {
734            marr *= val;
735         } else if (what==1) {
736            marr += val;
737         }
738
739// Put
740
741         spec.put(i, marr.getArray());
742      }
743   } else {
744
745// Get cursor location
746
747      IPosition start, end;
748      getCursorLocation (start, end, in);
749//
750      for (uInt i=0; i < tOut.nrow(); i++) {
751
752// Get
753
754         MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
755
756// Modify. More work than we would like to deal with the mask
757
758         Array<Float>& values = dataIn.getRWArray();
759         Array<Bool> mask(dataIn.getMask());
760//
761         Array<Float> values2 = values(start,end);
762         Array<Bool> mask2 = mask(start,end);
763         MaskedArray<Float> t(values2,mask2);
764         if (what==0) {
765            t *= val;
766         } else if (what==1) {
767            t += val;
768         }
769         values(start, end) = t.getArray();     // Write back into 'dataIn'
770
771// Put
772         spec.put(i, dataIn.getArray());
773      }
774   }
775//
776   return pOut;
777}
778
779
780
781void SDMath::getCursorLocation (IPosition& start, IPosition& end,
782                                const SDMemTable& in)
783{
784  const uInt nDim = 4;
785  const uInt i = in.getBeam();
786  const uInt j = in.getIF();
787  const uInt k = in.getPol();
788  const uInt n = in.nChan();
789//
790  start.resize(nDim);
791  start(0) = i;
792  start(1) = j;
793  start(2) = k;
794  start(3) = 0;
795//
796  end.resize(nDim);
797  end(0) = i;
798  end(1) = j;
799  end(2) = k;
800  end(3) = n-1;
801}
802
803
804void SDMath::convertWeightString (WeightType& wtType, const std::string& weightStr)
805{
806  String tStr(weightStr);
807  tStr.upcase();
808  if (tStr.contains(String("NONE"))) {
809     wtType = NONE;
810  } else if (tStr.contains(String("VAR"))) {
811     wtType = VAR;
812  } else if (tStr.contains(String("TSYS"))) {
813     wtType = TSYS;
814     throw (AipsError("T_sys weighting not yet implemented"));
815  } else {
816    throw (AipsError("Unrecognized weighting type"));
817  }
818}
819
820void SDMath::putDataInSDC (SDContainer& sc, const Array<Float>& data,
821                           const Array<Bool>& mask)
822{
823    sc.putSpectrum(data);
824//
825    Array<uChar> outflags(data.shape());
826    convertArray(outflags,!mask);
827    sc.putFlags(outflags);
828}
829
830
831SDMemTable* SDMath::localAveragePol(const SDMemTable& in, const Vector<Bool>& mask)
832//
833// Average all polarizations together, weighted by variance
834//
835{
836//   WeightType wtType = NONE;
837//   convertWeightString (wtType, weight);
838
839   const uInt nRows = in.nRow();
840   const uInt polAxis = 2;                     // Polarization axis
841   const uInt chanAxis = 3;                    // Spectrum axis
842
843// Create output Table and reshape number of polarizations
844
845  Bool clear=True;
846  SDMemTable* pTabOut = new SDMemTable(in, clear);
847  SDHeader header = pTabOut->getSDHeader();
848  header.npol = 1;
849  pTabOut->putSDHeader(header);
850
851// Shape of input and output data
852
853  const IPosition& shapeIn = in.rowAsMaskedArray(0u, False).shape();
854  IPosition shapeOut(shapeIn);
855  shapeOut(polAxis) = 1;                          // Average all polarizations
856//
857  const uInt nChan = shapeIn(chanAxis);
858  const IPosition vecShapeOut(4,1,1,1,nChan);     // A multi-dim form of a Vector shape
859  IPosition start(4), end(4);
860
861// Output arrays
862
863  Array<Float> outData(shapeOut, 0.0);
864  Array<Bool> outMask(shapeOut, True);
865  const IPosition axes(2, 2, 3);              // pol-channel plane
866//
867  const Bool useMask = (mask.nelements() == shapeIn(chanAxis));
868cerr << "nEl=" << mask.nelements() << endl;
869cerr << "useMask=" << useMask << endl;
870
871// Loop over rows
872
873   for (uInt iRow=0; iRow<nRows; iRow++) {
874
875// Get data for this row
876
877      MaskedArray<Float> marr(in.rowAsMaskedArray(iRow));
878      Array<Float>& arr = marr.getRWArray();
879      const Array<Bool>& barr = marr.getMask();
880
881// Make iterators to iterate by pol-channel planes
882
883      ReadOnlyArrayIterator<Float> itDataPlane(arr, axes);
884      ReadOnlyArrayIterator<Bool> itMaskPlane(barr, axes);
885
886// Accumulations
887
888      Float fac = 1.0;
889      Vector<Float> vecSum(nChan,0.0);
890
891// Iterate through data by pol-channel planes
892
893      while (!itDataPlane.pastEnd()) {
894
895// Iterate through plane by polarization  and accumulate Vectors
896
897        Vector<Float> t1(nChan); t1 = 0.0;
898        Vector<Bool> t2(nChan); t2 = True;
899        MaskedArray<Float> vecSum(t1,t2);
900        Float varSum = 0.0;
901        {
902           ReadOnlyVectorIterator<Float> itDataVec(itDataPlane.array(), 1);
903           ReadOnlyVectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
904           while (!itDataVec.pastEnd()) {     
905
906// Create MA of data & mask (optionally including OTF mask) and  get variance
907
908              if (useMask) {
909                 const MaskedArray<Float> spec(itDataVec.vector(),mask&&itMaskVec.vector());
910                 fac = 1.0 / variance(spec);
911              } else {
912                 const MaskedArray<Float> spec(itDataVec.vector(),itMaskVec.vector());
913                 fac = 1.0 / variance(spec);
914              }
915
916// Normalize spectrum (without OTF mask) and accumulate
917
918              const MaskedArray<Float> spec(fac*itDataVec.vector(), itMaskVec.vector());
919              vecSum += spec;
920              varSum += fac;
921
922// Next
923
924              itDataVec.next();
925              itMaskVec.next();
926           }
927        }
928
929// Normalize summed spectrum
930
931        vecSum /= varSum;
932
933// FInd position in input data array.  We are iterating by pol-channel
934// plane so all that will change is beam and IF and that's what we want.
935
936        IPosition pos = itDataPlane.pos();
937
938// Write out data. This is a bit messy. We have to reform the Vector
939// accumulator into an Array of shape (1,1,1,nChan)
940
941        start = pos;
942        end = pos;
943        end(chanAxis) = nChan-1;
944        outData(start,end) = vecSum.getArray().reform(vecShapeOut);
945        outMask(start,end) = vecSum.getMask().reform(vecShapeOut);
946
947// Step to next beam/IF combination
948
949        itDataPlane.next();
950        itMaskPlane.next();
951      }
952
953// Generate output container and write it to output table
954
955      SDContainer sc = in.getSDContainer();
956      sc.resize(shapeOut);
957//
958      putDataInSDC (sc, outData, outMask);
959      pTabOut->putSDContainer(sc);
960   }
961//
962  return pTabOut;
963}
Note: See TracBrowser for help on using the repository browser.