source: trunk/src/SDMath.cc @ 152

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

function 'add' and 'multiply' now take arg. doAll to
indicate whether operation to be applied to
all spectral or cursor selection only.

Combine functions 'localMultiply' and 'localAdd' into
'localOperate'

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