source: trunk/src/SDMath.cc@ 141

Last change on this file since 141 was 139, checked in by mar637, 20 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.