source: trunk/src/SDMath.cc @ 139

Last change on this file since 139 was 139, checked in by mar637, 19 years ago

Added inSitu version of multiply/scale

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.8 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 CountedPtr<SDMemTable>& in)
67//
68// Average all rows in Table in time
69//
70{
71  Table t = in->table();
72  ROArrayColumn<Float> tsys(t, "TSYS");
73  ROScalarColumn<Double> mjd(t, "TIME");
74  ROScalarColumn<String> srcn(t, "SRCNAME");
75  ROScalarColumn<Double> integr(t, "INTERVAL");
76  ROArrayColumn<uInt> freqidc(t, "FREQID");
77  IPosition ip = in->rowAsMaskedArray(0).shape();
78  Array<Float> outarr(ip); outarr =0.0;
79  Array<Float> narr(ip);narr = 0.0;
80  Array<Float> narrinc(ip);narrinc = 1.0;
81
82  Array<Float> tsarr(tsys.shape(0));
83  Array<Float> outtsarr(tsys.shape(0));
84  outtsarr =0.0;
85  tsys.get(0, tsarr);// this is probably unneccessary as tsys should
86  Double tme = 0.0;
87  Double inttime = 0.0;
88
89// Loop over rows
90
91  for (uInt i=0; i < t.nrow(); i++) {
92
93// Get data and accumulate sums
94
95    MaskedArray<Float> marr(in->rowAsMaskedArray(i));
96    outarr += marr;
97    MaskedArray<Float> n(narrinc,marr.getMask());
98    narr += n;
99
100// Accumulkate Tsys
101
102    tsys.get(i, tsarr);// this is probably unneccessary as tsys should
103    outtsarr += tsarr; // be constant
104    Double tmp;
105    mjd.get(i,tmp);
106    tme += tmp;// average time
107    integr.get(i,tmp);
108    inttime += tmp;
109  }
110
111// Average
112
113  MaskedArray<Float> nma(narr,(narr > Float(0)));
114  outarr /= nma;
115
116// Create container and put
117
118  Array<Bool> outflagsb = !(nma.getMask());
119  Array<uChar> outflags(outflagsb.shape());
120  convertArray(outflags,outflagsb);
121  SDContainer sc = in->getSDContainer();
122  Int n = t.nrow();
123  outtsarr /= Float(n);
124  sc.timestamp = tme/Double(n);
125  sc.interval = inttime;
126  String tstr; srcn.getScalar(0,tstr);// get sourcename of "mid" point
127  sc.sourcename = tstr;
128  Vector<uInt> tvec;
129  freqidc.get(0,tvec);
130  sc.putFreqMap(tvec);
131  sc.putTsys(outtsarr);
132  sc.scanid = 0;
133  sc.putSpectrum(outarr);
134  sc.putFlags(outflags);
135  SDMemTable* sdmt = new SDMemTable(*in,True);
136  sdmt->putSDContainer(sc);
137  return CountedPtr<SDMemTable>(sdmt);
138}
139
140CountedPtr<SDMemTable>
141SDMath::quotient(const CountedPtr<SDMemTable>& on,
142                 const CountedPtr<SDMemTable>& off)
143//
144// Compute quotient spectrum
145//
146{
147  const uInt nRows = on->nRow();
148  if (off->nRow() != nRows) {
149     throw (AipsError("Input Scan Tables must have the same number of rows"));
150  }
151
152// Input Tables and columns
153
154  Table ton = on->table();
155  Table toff = off->table();
156  ROArrayColumn<Float> tsys(toff, "TSYS");
157  ROScalarColumn<Double> mjd(ton, "TIME");
158  ROScalarColumn<Double> integr(ton, "INTERVAL");
159  ROScalarColumn<String> srcn(ton, "SRCNAME");
160  ROArrayColumn<uInt> freqidc(ton, "FREQID");
161
162// Output Table cloned from input
163
164  SDMemTable* sdmt = new SDMemTable(*on, True);
165
166// Loop over rows
167
168  for (uInt i=0; i<nRows; i++) {
169     MaskedArray<Float> mon(on->rowAsMaskedArray(i));
170     MaskedArray<Float> moff(off->rowAsMaskedArray(i));
171     IPosition ipon = mon.shape();
172     IPosition ipoff = moff.shape();
173//
174     Array<Float> tsarr; 
175     tsys.get(i, tsarr);
176     if (ipon != ipoff && ipon != tsarr.shape()) {
177       throw(AipsError("on/off not conformant"));
178     }
179
180// Compute quotient
181
182     MaskedArray<Float> tmp = (mon-moff);
183     Array<Float> out(tmp.getArray());
184     out /= moff;
185     out *= tsarr;
186     Array<Bool> outflagsb = !(mon.getMask() && moff.getMask());
187     Array<uChar> outflags(outflagsb.shape());
188     convertArray(outflags,outflagsb);
189
190// Fill container for this row
191
192     SDContainer sc = on->getSDContainer();
193     sc.putTsys(tsarr);
194     sc.scanid = 0;
195     sc.putSpectrum(out);
196     sc.putFlags(outflags);
197
198// Put new row in output Table
199
200     sdmt->putSDContainer(sc);
201  }
202//
203  return CountedPtr<SDMemTable>(sdmt);
204}
205
206void SDMath::multiplyInSitu(SDMemTable* in, Float factor) {
207  SDMemTable* sdmt = new SDMemTable(*in);
208  Table t = sdmt->table();
209  ArrayColumn<Float> spec(t,"SPECTRA"); 
210  for (uInt i=0; i < t.nrow(); i++) {
211    MaskedArray<Float> marr(sdmt->rowAsMaskedArray(i));
212    marr *= factor;
213    spec.put(i, marr.getArray());
214  }
215  in = sdmt;
216  delete sdmt;sdmt=0;
217}
218
219CountedPtr<SDMemTable>
220SDMath::multiply(const CountedPtr<SDMemTable>& in, Float factor)
221//
222// Multiply values by factor
223//
224{
225  SDMemTable* sdmt = new SDMemTable(*in);
226  Table t = sdmt->table();
227  ArrayColumn<Float> spec(t,"SPECTRA");
228
229  for (uInt i=0; i < t.nrow(); i++) {
230    MaskedArray<Float> marr(sdmt->rowAsMaskedArray(i));
231    marr *= factor;
232    spec.put(i, marr.getArray());
233  }
234  return CountedPtr<SDMemTable>(sdmt);
235}
236
237CountedPtr<SDMemTable>
238SDMath::add(const CountedPtr<SDMemTable>& in, Float offset)
239//
240// Add offset to values
241//
242{
243  SDMemTable* sdmt = new SDMemTable(*in);
244
245  Table t = sdmt->table();
246  ArrayColumn<Float> spec(t,"SPECTRA");
247
248  for (uInt i=0; i < t.nrow(); i++) {
249    MaskedArray<Float> marr(sdmt->rowAsMaskedArray(i));
250    marr += offset;
251    spec.put(i, marr.getArray());
252  }
253  return CountedPtr<SDMemTable>(sdmt);
254}
255
256
257CountedPtr<SDMemTable>
258SDMath::hanning(const CountedPtr<SDMemTable>& in)
259//
260// Hanning smooth each row
261// Should Tsys be smoothed ?
262//
263{
264  SDMemTable* sdmt = new SDMemTable(*in,True);
265
266// Loop over rows in Table
267
268  for (uInt ri=0; ri < in->nRow(); ++ri) {
269
270// Get data
271   
272    const MaskedArray<Float>& marr(in->rowAsMaskedArray(ri));
273    Array<Float> arr = marr.getArray();
274    Array<Bool> barr = marr.getMask();
275
276// Smooth along the channels axis
277
278    uInt axis = 3;
279    VectorIterator<Float> itData(arr, axis);
280    VectorIterator<Bool> itMask(barr, axis);
281    Vector<Float> outv;
282    Vector<Bool> outm;
283    while (!itData.pastEnd()) {
284       mathutil::hanning(outv, outm, itData.vector(), itMask.vector());
285       itData.vector() = outv;                                                 
286       itMask.vector() = outm;
287//
288       itData.next();
289       itMask.next();
290    }
291
292// Create and put back
293
294    Array<uChar> outflags(barr.shape());
295    convertArray(outflags,!barr);
296    SDContainer sc = in->getSDContainer(ri);
297    sc.putSpectrum(arr);
298    sc.putFlags(outflags);
299    sdmt->putSDContainer(sc);
300  }
301  return CountedPtr<SDMemTable>(sdmt);
302}
303
304
305
306CountedPtr<SDMemTable> SDMath::averages(const Block<CountedPtr<SDMemTable> >& in,
307                                        const Vector<Bool>& mask)
308//
309// Noise weighted averaging of spectra from many Tables.  Tables can have different
310// number of rows. 
311//
312{
313
314// Setup
315
316  const uInt axis = 3;                                 // Spectral axis
317  IPosition shp = in[0]->rowAsMaskedArray(0).shape();
318  Array<Float> arr(shp);
319  Array<Bool> barr(shp);
320  Double sumInterval = 0.0;
321  const Bool useMask = (mask.nelements() == shp(axis));
322
323// Create data accumulation MaskedArray. We accumulate for each
324// channel,if,pol,beam
325
326  Array<Float> zero(shp); zero=0.0;
327  Array<Bool> good(shp); good = True;
328  MaskedArray<Float> sum(zero,good);
329
330// Create accumulation Array for variance. We accumulate for
331// each if,pol,beam, but average over channel
332
333  const uInt nAxesSub = shp.nelements() - 1;
334  IPosition shp2(nAxesSub);
335  for (uInt i=0,j=0; i<(nAxesSub+1); i++) {
336     if (i!=axis) {
337       shp2(j) = shp(i);
338       j++;
339     }
340  }
341  Array<Float> sumSq(shp2);
342  sumSq = 0.0;
343  IPosition pos2(nAxesSub,0);                        // FOr indexing
344// 
345  Float fac = 1.0;
346  const uInt nTables = in.nelements();
347  for (uInt iTab=0; iTab<nTables; iTab++) {
348     const uInt nRows = in[iTab]->nRow();
349     sumInterval += nRows * in[iTab]->getInterval();   // Sum of time intervals
350//
351     for (uInt iRow=0; iRow<nRows; iRow++) {
352
353// Check conforms
354
355        IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();
356        if (!shp.isEqual(shp2)) {
357           throw (AipsError("Shapes for all rows must be the same"));
358        }
359
360// Get data and deconstruct
361 
362        MaskedArray<Float> marr(in[iTab]->rowAsMaskedArray(iRow));
363        Array<Float>& arr = marr.getRWArray();                     // writable reference
364        const Array<Bool>& barr = marr.getMask();                  // RO reference
365
366// We are going to average the data, weighted by the noise for each
367// pol, beam and IF. So therefore we need to iterate through by
368// spectra (axis 3)
369
370        VectorIterator<Float> itData(arr, axis);
371        ReadOnlyVectorIterator<Bool> itMask(barr, axis);
372        while (!itData.pastEnd()) {
373
374// Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor
375
376          if (useMask) {
377             MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());
378             fac = 1.0/variance(tmp);
379          } else {
380             MaskedArray<Float> tmp(itData.vector(),itMask.vector());
381             fac = 1.0/variance(tmp);
382          }
383
384// Scale data
385
386          itData.vector() *= fac;
387
388// Accumulate variance per if/pol/beam averaged over spectrum
389// This method to get pos2 from itData.pos() is only valid
390// because the spectral axis is the last one (so we can just
391// copy the first nAXesSub positions out)
392
393          pos2 = itData.pos().getFirst(nAxesSub);
394          sumSq(pos2) += fac;
395//
396          itData.next();
397          itMask.next();
398        }   
399
400// Accumulate sums
401
402       sum += marr;
403    }
404  }
405
406// Normalize by the sum of the 1/var. 
407
408  Array<Float>& data = sum.getRWArray();   
409  VectorIterator<Float> itData(data, axis);
410  while (!itData.pastEnd()) {
411     pos2 = itData.pos().getFirst(nAxesSub);           // See comments above
412     itData.vector() /= sumSq(pos2);
413     itData.next();
414  }   
415
416// Create and fill output
417
418  Array<uChar> outflags(shp);
419  convertArray(outflags,!(sum.getMask()));
420//
421  SDContainer sc = in[0]->getSDContainer();     // CLone from first container of first Table
422  sc.putSpectrum(data);
423  sc.putFlags(outflags);
424  sc.interval = sumInterval;
425//
426  SDMemTable* sdmt = new SDMemTable(*in[0],True);  // CLone from first Table
427  sdmt->putSDContainer(sc);
428  return CountedPtr<SDMemTable>(sdmt);
429}
430
431
432CountedPtr<SDMemTable>
433SDMath::averagePol(const CountedPtr<SDMemTable>& in,
434                   const Vector<Bool>& mask)
435{
436   const uInt nRows = in->nRow();
437   const uInt axis = 3;                        // Spectrum
438   const IPosition axes(2, 2, 3);              // pol-channel plane
439
440// Create output Table
441
442  SDMemTable* sdmt = new SDMemTable(*in, True);
443
444// Loop over rows
445
446   for (uInt iRow=0; iRow<nRows; iRow++) {
447
448// Get data for this row
449
450      MaskedArray<Float> marr(in->rowAsMaskedArray(iRow));
451      Array<Float>& arr = marr.getRWArray();
452      const Array<Bool>& barr = marr.getMask();
453//
454      IPosition shp = marr.shape();
455      const Bool useMask = (mask.nelements() == shp(axis));
456      const uInt nChan = shp(axis);
457
458// Make iterators to iterate by pol-channel planes
459
460     ArrayIterator<Float> itDataPlane(arr, axes);
461     ReadOnlyArrayIterator<Bool> itMaskPlane(barr, axes);
462
463// Accumulations
464
465     Float fac = 0.0;
466     Vector<Float> vecSum(nChan,0.0);
467
468// Iterate by plane
469
470     while (!itDataPlane.pastEnd()) {
471
472// Iterate through pol-channel plane by spectrum
473
474        Vector<Float> t1(nChan); t1 = 0.0;
475        Vector<Bool> t2(nChan); t2 = True;
476        MaskedArray<Float> vecSum(t1,t2);
477        Float varSum = 0.0;
478        {
479           ReadOnlyVectorIterator<Float> itDataVec(itDataPlane.array(), 1);
480           ReadOnlyVectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
481           while (!itDataVec.pastEnd()) {     
482
483// Create MA of data & mask (optionally including OTF mask) and  get variance
484
485              if (useMask) {
486                 const MaskedArray<Float> spec(itDataVec.vector(),mask&&itMaskVec.vector());
487                 fac = 1.0 / variance(spec);
488              } else {
489                 const MaskedArray<Float> spec(itDataVec.vector(),itMaskVec.vector());
490                 fac = 1.0 / variance(spec);
491              }
492
493// Normalize spectrum (without OTF mask) and accumulate
494
495              const MaskedArray<Float> spec(fac*itDataVec.vector(), itMaskVec.vector());
496              vecSum += spec;
497              varSum += fac;
498
499// Next
500
501              itDataVec.next();
502              itMaskVec.next();
503           }
504        }
505
506// Normalize summed spectrum
507
508        vecSum /= varSum;
509
510// We have formed the weighted averaged spectrum from all polarizations
511// for this beam and IF.  Now replicate the spectrum to all polarizations
512
513        {
514           VectorIterator<Float> itDataVec(itDataPlane.array(), 1);  // Writes back into 'arr'
515           const Vector<Float>& vecSumData = vecSum.getArray();      // It *is* a Vector
516//
517           while (!itDataVec.pastEnd()) {     
518              itDataVec.vector() = vecSumData;
519              itDataVec.next();
520           }
521        }
522
523// Step to next beam/IF combination
524
525        itDataPlane.next();
526        itMaskPlane.next();
527     }
528
529// Generate output container and write it to output table
530
531     SDContainer sc = in->getSDContainer();
532     Array<uChar> outflags(barr.shape());
533     convertArray(outflags,!barr);
534     sc.putSpectrum(arr);
535     sc.putFlags(outflags);
536     sdmt->putSDContainer(sc);
537   }
538//
539  return CountedPtr<SDMemTable>(sdmt);
540}
541
542
543CountedPtr<SDMemTable> SDMath::bin(const CountedPtr<SDMemTable>& in,
544                                   Int width)
545{
546  SDHeader sh = in->getSDHeader();
547  SDMemTable* sdmt = new SDMemTable(*in,True);
548
549// Bin up SpectralCoordinates
550
551  IPosition factors(1);
552  factors(0) = width;
553  for (uInt j=0; j<in->nCoordinates(); ++j) {
554    CoordinateSystem cSys;
555    cSys.addCoordinate(in->getCoordinate(j));
556    CoordinateSystem cSysBin =
557      CoordinateUtil::makeBinnedCoordinateSystem (factors, cSys, False);
558//
559    SpectralCoordinate sCBin = cSysBin.spectralCoordinate(0);
560    sdmt->setCoordinate(sCBin, j);
561  }
562
563// Use RebinLattice to find shape
564
565  IPosition shapeIn(1,sh.nchan);
566  IPosition shapeOut = RebinLattice<Float>::rebinShape (shapeIn, factors);
567  sh.nchan = shapeOut(0);
568  sdmt->putSDHeader(sh);
569
570
571// Loop over rows and bin along channel axis
572 
573  const uInt axis = 3;
574  for (uInt i=0; i < in->nRow(); ++i) {
575    SDContainer sc = in->getSDContainer(i);
576//
577    Array<Float> tSys(sc.getTsys());                           // Get it out before sc changes shape
578
579// Bin up spectrum
580
581    MaskedArray<Float> marr(in->rowAsMaskedArray(i));
582    MaskedArray<Float> marrout;
583    LatticeUtilities::bin(marrout, marr, axis, width);
584
585// Put back the binned data and flags
586
587    IPosition ip2 = marrout.shape();
588    sc.resize(ip2);
589    sc.putSpectrum(marrout.getArray());
590//
591    Array<uChar> outflags(ip2);
592    convertArray(outflags,!(marrout.getMask()));
593    sc.putFlags(outflags);
594
595// Bin up Tsys. 
596
597    Array<Bool> allGood(tSys.shape(),True);
598    MaskedArray<Float> tSysIn(tSys, allGood, True);
599//
600    MaskedArray<Float> tSysOut;   
601    LatticeUtilities::bin(tSysOut, tSysIn, axis, width);
602    sc.putTsys(tSysOut.getArray());
603    sdmt->putSDContainer(sc);
604  }
605  return CountedPtr<SDMemTable>(sdmt);
606}
607
608
609
610std::vector<float> SDMath::statistic (const CountedPtr<SDMemTable>& in,
611                                       const std::vector<bool>& mask,
612                                       const std::string& which)
613//
614// Perhaps iteration over pol/beam/if should be in here
615// and inside the nrow iteration ?
616//
617{
618  const uInt nRow = in->nRow();
619  std::vector<float> result(nRow);
620  Vector<Bool> msk(mask);
621
622// Specify cursor location
623
624  uInt i = in->getBeam();
625  uInt j = in->getIF();
626  uInt k = in->getPol();
627  IPosition start(4,i,j,k,0);
628  IPosition end(4,i,j,k,in->nChan()-1);
629
630// Loop over rows
631
632  const uInt nEl = msk.nelements();
633  for (uInt ii=0; ii < in->nRow(); ++ii) {
634
635// Get row and deconstruct
636
637     MaskedArray<Float> marr(in->rowAsMaskedArray(ii));
638     Array<Float> arr = marr.getArray();
639     Array<Bool> barr = marr.getMask();
640
641// Access desired piece of data
642
643     Array<Float> v((arr(start,end)).nonDegenerate());
644     Array<Bool> m((barr(start,end)).nonDegenerate());
645
646// Apply OTF mask
647
648     MaskedArray<Float> tmp;
649     if (m.nelements()==nEl) {
650       tmp.setData(v,m&&msk);
651     } else {
652       tmp.setData(v,m);
653     }
654
655// Get statistic
656
657     result[ii] = SDMath::theStatistic(which, tmp);
658  }
659//
660  return result;
661}
662
663
664float SDMath::theStatistic(const std::string& which,  const casa::MaskedArray<Float>& data)
665{
666   String str(which);
667   str.upcase();
668   if (str.contains(String("MIN"))) {
669      return min(data);
670   } else if (str.contains(String("MAX"))) {
671      return max(data);
672   } else if (str.contains(String("SUMSQ"))) {
673      return sumsquares(data);
674   } else if (str.contains(String("SUM"))) {
675      return sum(data);
676   } else if (str.contains(String("MEAN"))) {
677      return mean(data);
678   } else if (str.contains(String("VAR"))) {
679      return variance(data);
680   } else if (str.contains(String("STDDEV"))) {
681      return stddev(data);
682   } else if (str.contains(String("AVDEV"))) {
683      return avdev(data);
684   } else if (str.contains(String("RMS"))) {
685      uInt n = data.nelementsValid();
686      return sqrt(sumsquares(data)/n);
687   } else if (str.contains(String("MED"))) {
688      return median(data);
689   }
690}
Note: See TracBrowser for help on using the repository browser.