source: trunk/src/SDMath.cc@ 130

Last change on this file since 130 was 130, checked in by kil064, 20 years ago

Rewrite pretty much all of it to

  • use iterators rather than indexed for loops
  • loop over nrows

Fixed some minor bugs here and there
Added function 'statistics' to provide more statistics beyond standard deviation

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