source: trunk/src/SDMath.cc@ 209

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