source: trunk/src/SDMath.cc@ 176

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

Add cursor selection to function 'hanning' (arg. 'all')

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