source: trunk/src/SDMath.cc@ 318

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

add interpolatiun method argument to function 'frequencyAlign'

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.2 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>
[234]44#include <casa/BasicMath/Math.h>
[221]45#include <casa/Containers/Block.h>
[262]46#include <casa/Exceptions.h>
47#include <casa/Quanta/Quantum.h>
48#include <casa/Quanta/Unit.h>
49#include <casa/Quanta/MVEpoch.h>
[221]50#include <casa/Quanta/QC.h>
[272]51#include <casa/Quanta/MVTime.h>
[177]52#include <casa/Utilities/Assert.h>
[2]53
[262]54#include <coordinates/Coordinates/SpectralCoordinate.h>
55#include <coordinates/Coordinates/CoordinateSystem.h>
56#include <coordinates/Coordinates/CoordinateUtil.h>
[309]57#include <coordinates/Coordinates/FrequencyAligner.h>
[262]58
59#include <lattices/Lattices/LatticeUtilities.h>
60#include <lattices/Lattices/RebinLattice.h>
61
62#include <measures/Measures/MEpoch.h>
63#include <measures/Measures/MDirection.h>
64#include <measures/Measures/MPosition.h>
65
[177]66#include <scimath/Mathematics/VectorKernel.h>
67#include <scimath/Mathematics/Convolver.h>
[227]68#include <scimath/Mathematics/InterpolateArray1D.h>
[234]69#include <scimath/Functionals/Polynomial.h>
[177]70
[81]71#include <tables/Tables/Table.h>
72#include <tables/Tables/ScalarColumn.h>
73#include <tables/Tables/ArrayColumn.h>
[227]74#include <tables/Tables/ReadAsciiTable.h>
[2]75
[38]76#include "MathUtils.h"
[232]77#include "SDDefs.h"
[2]78#include "SDContainer.h"
79#include "SDMemTable.h"
80
81#include "SDMath.h"
82
[125]83using namespace casa;
[83]84using namespace asap;
[2]85
[170]86
87SDMath::SDMath()
88{;}
89
[185]90SDMath::SDMath(const SDMath& other)
[170]91{
92
93// No state
94
95}
96
97SDMath& SDMath::operator=(const SDMath& other)
98{
99 if (this != &other) {
100// No state
101 }
102 return *this;
103}
104
[183]105SDMath::~SDMath()
106{;}
[170]107
[183]108
[262]109
[317]110SDMemTable* SDMath::frequencyAlignment (const SDMemTable& in, const String& refTime, const String& method) const
[262]111{
112
[309]113// Get frame info from Table
[262]114
115 std::vector<std::string> info = in.getCoordInfo();
[294]116
[309]117// Parse frequency system
[294]118
[309]119 String systemStr(info[1]);
120 String baseSystemStr(info[3]);
121 if (baseSystemStr==systemStr) {
122 throw(AipsError("You have not set a frequency frame different from the initial - use function set_freqframe"));
[262]123 }
[309]124//
125 MFrequency::Types freqSystem;
126 MFrequency::getType(freqSystem, systemStr);
[294]127
[267]128// Do it
[262]129
[317]130 return frequencyAlign (in, freqSystem, refTime, method);
[267]131}
[262]132
133
134
[185]135CountedPtr<SDMemTable> SDMath::average(const Block<CountedPtr<SDMemTable> >& in,
136 const Vector<Bool>& mask, Bool scanAv,
[309]137 const String& weightStr, Bool alignFreq) const
[130]138//
[144]139// Weighted averaging of spectra from one or more Tables.
[130]140//
141{
[2]142
[163]143// Convert weight type
144
145 WeightType wtType = NONE;
[185]146 convertWeightString(wtType, weightStr);
[163]147
[144]148// Create output Table by cloning from the first table
[2]149
[144]150 SDMemTable* pTabOut = new SDMemTable(*in[0],True);
[130]151
[144]152// Setup
[130]153
[144]154 IPosition shp = in[0]->rowAsMaskedArray(0).shape(); // Must not change
155 Array<Float> arr(shp);
156 Array<Bool> barr(shp);
[221]157 const Bool useMask = (mask.nelements() == shp(asap::ChanAxis));
[130]158
[144]159// Columns from Tables
[130]160
[144]161 ROArrayColumn<Float> tSysCol;
162 ROScalarColumn<Double> mjdCol;
163 ROScalarColumn<String> srcNameCol;
164 ROScalarColumn<Double> intCol;
165 ROArrayColumn<uInt> fqIDCol;
[130]166
[144]167// Create accumulation MaskedArray. We accumulate for each channel,if,pol,beam
168// Note that the mask of the accumulation array will ALWAYS remain ALL True.
169// The MA is only used so that when data which is masked Bad is added to it,
170// that data does not contribute.
171
172 Array<Float> zero(shp);
173 zero=0.0;
174 Array<Bool> good(shp);
175 good = True;
176 MaskedArray<Float> sum(zero,good);
177
178// Counter arrays
179
180 Array<Float> nPts(shp); // Number of points
181 nPts = 0.0;
182 Array<Float> nInc(shp); // Increment
183 nInc = 1.0;
184
185// Create accumulation Array for variance. We accumulate for
186// each if,pol,beam, but average over channel. So we need
187// a shape with one less axis dropping channels.
188
189 const uInt nAxesSub = shp.nelements() - 1;
190 IPosition shp2(nAxesSub);
191 for (uInt i=0,j=0; i<(nAxesSub+1); i++) {
[221]192 if (i!=asap::ChanAxis) {
[144]193 shp2(j) = shp(i);
194 j++;
195 }
[2]196 }
[144]197 Array<Float> sumSq(shp2);
198 sumSq = 0.0;
199 IPosition pos2(nAxesSub,0); // For indexing
[130]200
[144]201// Time-related accumulators
[130]202
[144]203 Double time;
204 Double timeSum = 0.0;
205 Double intSum = 0.0;
206 Double interval = 0.0;
[130]207
[144]208// To get the right shape for the Tsys accumulator we need to
209// access a column from the first table. The shape of this
210// array must not change
[130]211
[144]212 Array<Float> tSysSum;
213 {
214 const Table& tabIn = in[0]->table();
215 tSysCol.attach(tabIn,"TSYS");
216 tSysSum.resize(tSysCol.shape(0));
217 }
218 tSysSum =0.0;
219 Array<Float> tSys;
220
221// Scan and row tracking
222
223 Int oldScanID = 0;
224 Int outScanID = 0;
225 Int scanID = 0;
226 Int rowStart = 0;
227 Int nAccum = 0;
228 Int tableStart = 0;
229
230// Source and FreqID
231
232 String sourceName, oldSourceName, sourceNameStart;
233 Vector<uInt> freqID, freqIDStart, oldFreqID;
234
235// Loop over tables
236
237 Float fac = 1.0;
238 const uInt nTables = in.nelements();
239 for (uInt iTab=0; iTab<nTables; iTab++) {
240
[309]241// Should check that the frequency tables don't change if doing FreqAlignment
[221]242
[144]243// Attach columns to Table
244
245 const Table& tabIn = in[iTab]->table();
246 tSysCol.attach(tabIn, "TSYS");
247 mjdCol.attach(tabIn, "TIME");
248 srcNameCol.attach(tabIn, "SRCNAME");
249 intCol.attach(tabIn, "INTERVAL");
250 fqIDCol.attach(tabIn, "FREQID");
251
252// Loop over rows in Table
253
254 const uInt nRows = in[iTab]->nRow();
255 for (uInt iRow=0; iRow<nRows; iRow++) {
256
257// Check conformance
258
259 IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();
260 if (!shp.isEqual(shp2)) {
261 throw (AipsError("Shapes for all rows must be the same"));
262 }
263
264// If we are not doing scan averages, make checks for source and
265// frequency setup and warn if averaging across them
266
267// Get copy of Scan Container for this row
268
269 SDContainer sc = in[iTab]->getSDContainer(iRow);
270 scanID = sc.scanid;
271
272// Get quantities from columns
273
274 srcNameCol.getScalar(iRow, sourceName);
275 mjdCol.get(iRow, time);
276 tSysCol.get(iRow, tSys);
277 intCol.get(iRow, interval);
278 fqIDCol.get(iRow, freqID);
279
280// Initialize first source and freqID
281
282 if (iRow==0 && iTab==0) {
283 sourceNameStart = sourceName;
284 freqIDStart = freqID;
285 }
286
287// If we are doing scan averages, see if we are at the end of an
288// accumulation period (scan). We must check soutce names too,
289// since we might have two tables with one scan each but different
290// source names; we shouldn't average different sources together
291
292 if (scanAv && ( (scanID != oldScanID) ||
293 (iRow==0 && iTab>0 && sourceName!=oldSourceName))) {
294
295// Normalize data in 'sum' accumulation array according to weighting scheme
296
[221]297 normalize(sum, sumSq, nPts, wtType, asap::ChanAxis, nAxesSub);
[144]298
299// Fill scan container. The source and freqID come from the
300// first row of the first table that went into this average (
301// should be the same for all rows in the scan average)
302
303 Float nR(nAccum);
[185]304 fillSDC(sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
[144]305 timeSum/nR, intSum, sourceNameStart, freqIDStart);
306
307// Write container out to Table
308
309 pTabOut->putSDContainer(sc);
310
311// Reset accumulators
312
313 sum = 0.0;
314 sumSq = 0.0;
315 nAccum = 0;
316//
317 tSysSum =0.0;
318 timeSum = 0.0;
319 intSum = 0.0;
[221]320 nPts = 0.0;
[144]321
322// Increment
323
324 rowStart = iRow; // First row for next accumulation
325 tableStart = iTab; // First table for next accumulation
326 sourceNameStart = sourceName; // First source name for next accumulation
327 freqIDStart = freqID; // First FreqID for next accumulation
328//
329 oldScanID = scanID;
330 outScanID += 1; // Scan ID for next accumulation period
[227]331 }
[144]332
[146]333// Accumulate
[144]334
[185]335 accumulate(timeSum, intSum, nAccum, sum, sumSq, nPts, tSysSum,
[221]336 tSys, nInc, mask, time, interval, in, iTab, iRow, asap::ChanAxis,
[146]337 nAxesSub, useMask, wtType);
[144]338//
339 oldSourceName = sourceName;
340 oldFreqID = freqID;
[184]341 }
[144]342 }
343
344// OK at this point we have accumulation data which is either
345// - accumulated from all tables into one row
346// or
347// - accumulated from the last scan average
348//
349// Normalize data in 'sum' accumulation array according to weighting scheme
[221]350 normalize(sum, sumSq, nPts, wtType, asap::ChanAxis, nAxesSub);
[144]351
352// Create and fill container. The container we clone will be from
353// the last Table and the first row that went into the current
354// accumulation. It probably doesn't matter that much really...
355
356 Float nR(nAccum);
357 SDContainer sc = in[tableStart]->getSDContainer(rowStart);
[185]358 fillSDC(sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
[144]359 timeSum/nR, intSum, sourceNameStart, freqIDStart);
[221]360 pTabOut->putSDContainer(sc);
[304]361 pTabOut->resetCursor();
[144]362//
363 return CountedPtr<SDMemTable>(pTabOut);
[2]364}
[9]365
[144]366
367
[248]368CountedPtr<SDMemTable> SDMath::binaryOperate (const CountedPtr<SDMemTable>& left,
369 const CountedPtr<SDMemTable>& right,
[294]370 const String& op, Bool preserve,
371 Bool doTSys) const
[185]372{
[85]373
[248]374// Check operator
[130]375
[234]376 String op2(op);
377 op2.upcase();
378 uInt what = 0;
379 if (op2=="ADD") {
380 what = 0;
381 } else if (op2=="SUB") {
382 what = 1;
383 } else if (op2=="MUL") {
384 what = 2;
385 } else if (op2=="DIV") {
386 what = 3;
[248]387 } else if (op2=="QUOTIENT") {
388 what = 4;
[294]389 doTSys = True;
[234]390 } else {
[248]391 throw( AipsError("Unrecognized operation"));
[234]392 }
393
394// Check rows
395
[248]396 const uInt nRowLeft = left->nRow();
397 const uInt nRowRight = right->nRow();
398 Bool ok = (nRowRight==1&&nRowLeft>0) ||
399 (nRowRight>=1&&nRowLeft==nRowRight);
400 if (!ok) {
401 throw (AipsError("The right Scan Table can have one row or the same number of rows as the left Scan Table"));
[234]402 }
403
[248]404// Input Tables
[234]405
406 const Table& tLeft = left->table();
407 const Table& tRight = right->table();
[248]408
409// TSys columns
410
[294]411 ROArrayColumn<Float> tSysLeftCol, tSysRightCol;
412 if (doTSys) {
413 tSysLeftCol.attach(tLeft, "TSYS");
414 tSysRightCol.attach(tRight, "TSYS");
415 }
[234]416
[248]417// First row for right
[234]418
[248]419 Array<Float> tSysLeftArr, tSysRightArr;
[294]420 if (doTSys) tSysRightCol.get(0, tSysRightArr);
[248]421 MaskedArray<Float>* pMRight = new MaskedArray<Float>(right->rowAsMaskedArray(0));
422 IPosition shpRight = pMRight->shape();
423
424// Output Table cloned from left
425
[234]426 SDMemTable* pTabOut = new SDMemTable(*left, True);
427
428// Loop over rows
429
[248]430 for (uInt i=0; i<nRowLeft; i++) {
[234]431
432// Get data
[248]433
[234]434 MaskedArray<Float> mLeft(left->rowAsMaskedArray(i));
[248]435 IPosition shpLeft = mLeft.shape();
[294]436 if (doTSys) tSysLeftCol.get(i, tSysLeftArr);
[234]437//
[248]438 if (nRowRight>1) {
439 delete pMRight;
440 pMRight = new MaskedArray<Float>(right->rowAsMaskedArray(i));
441 shpRight = pMRight->shape();
[294]442 if (doTSys) tSysRightCol.get(i, tSysRightArr);
[234]443 }
[248]444//
445 if (!shpRight.isEqual(shpLeft)) {
446 throw(AipsError("left and right scan tables are not conformant"));
447 }
[294]448 if (doTSys) {
449 if (!tSysRightArr.shape().isEqual(tSysRightArr.shape())) {
450 throw(AipsError("left and right Tsys data are not conformant"));
451 }
452 if (!shpRight.isEqual(tSysRightArr.shape())) {
453 throw(AipsError("left and right scan tables are not conformant"));
454 }
[248]455 }
[234]456
457// Make container
458
459 SDContainer sc = left->getSDContainer(i);
460
461// Operate on data and TSys
462
463 if (what==0) {
[248]464 MaskedArray<Float> tmp = mLeft + *pMRight;
[234]465 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
[294]466 if (doTSys) sc.putTsys(tSysLeftArr+tSysRightArr);
[234]467 } else if (what==1) {
[248]468 MaskedArray<Float> tmp = mLeft - *pMRight;
[234]469 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
[294]470 if (doTSys) sc.putTsys(tSysLeftArr-tSysRightArr);
[234]471 } else if (what==2) {
[248]472 MaskedArray<Float> tmp = mLeft * *pMRight;
[234]473 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
[294]474 if (doTSys) sc.putTsys(tSysLeftArr*tSysRightArr);
[234]475 } else if (what==3) {
[248]476 MaskedArray<Float> tmp = mLeft / *pMRight;
[234]477 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
[294]478 if (doTSys) sc.putTsys(tSysLeftArr/tSysRightArr);
[248]479 } else if (what==4) {
480 if (preserve) {
481 MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) - tSysRightArr;
482 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
483 } else {
484 MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) - tSysLeftArr;
485 putDataInSDC(sc, tmp.getArray(), tmp.getMask());
486 }
487 sc.putTsys(tSysRightArr);
[234]488 }
489
490// Put new row in output Table
491
[171]492 pTabOut->putSDContainer(sc);
[130]493 }
[248]494 if (pMRight) delete pMRight;
[304]495 pTabOut->resetCursor();
[130]496//
[171]497 return CountedPtr<SDMemTable>(pTabOut);
[9]498}
[48]499
[146]500
501
[185]502std::vector<float> SDMath::statistic(const CountedPtr<SDMemTable>& in,
[234]503 const Vector<Bool>& mask,
504 const String& which, Int row) const
[130]505//
506// Perhaps iteration over pol/beam/if should be in here
507// and inside the nrow iteration ?
508//
509{
510 const uInt nRow = in->nRow();
511
512// Specify cursor location
513
[152]514 IPosition start, end;
[185]515 getCursorLocation(start, end, *in);
[130]516
517// Loop over rows
518
[234]519 const uInt nEl = mask.nelements();
520 uInt iStart = 0;
521 uInt iEnd = in->nRow()-1;
522//
523 if (row>=0) {
524 iStart = row;
525 iEnd = row;
526 }
527//
528 std::vector<float> result(iEnd-iStart+1);
529 for (uInt ii=iStart; ii <= iEnd; ++ii) {
[130]530
531// Get row and deconstruct
532
533 MaskedArray<Float> marr(in->rowAsMaskedArray(ii));
534 Array<Float> arr = marr.getArray();
535 Array<Bool> barr = marr.getMask();
536
537// Access desired piece of data
538
539 Array<Float> v((arr(start,end)).nonDegenerate());
540 Array<Bool> m((barr(start,end)).nonDegenerate());
541
542// Apply OTF mask
543
544 MaskedArray<Float> tmp;
545 if (m.nelements()==nEl) {
[234]546 tmp.setData(v,m&&mask);
[130]547 } else {
548 tmp.setData(v,m);
549 }
550
551// Get statistic
552
[234]553 result[ii-iStart] = mathutil::statistics(which, tmp);
[130]554 }
555//
556 return result;
557}
558
[146]559
[234]560SDMemTable* SDMath::bin(const SDMemTable& in, Int width) const
[144]561{
[169]562 SDHeader sh = in.getSDHeader();
563 SDMemTable* pTabOut = new SDMemTable(in, True);
[163]564
[169]565// Bin up SpectralCoordinates
[163]566
[169]567 IPosition factors(1);
568 factors(0) = width;
569 for (uInt j=0; j<in.nCoordinates(); ++j) {
570 CoordinateSystem cSys;
[288]571 cSys.addCoordinate(in.getSpectralCoordinate(j));
[169]572 CoordinateSystem cSysBin =
[185]573 CoordinateUtil::makeBinnedCoordinateSystem(factors, cSys, False);
[169]574//
575 SpectralCoordinate sCBin = cSysBin.spectralCoordinate(0);
576 pTabOut->setCoordinate(sCBin, j);
577 }
[163]578
[169]579// Use RebinLattice to find shape
[130]580
[169]581 IPosition shapeIn(1,sh.nchan);
[185]582 IPosition shapeOut = RebinLattice<Float>::rebinShape(shapeIn, factors);
[169]583 sh.nchan = shapeOut(0);
584 pTabOut->putSDHeader(sh);
[144]585
[169]586// Loop over rows and bin along channel axis
587
588 for (uInt i=0; i < in.nRow(); ++i) {
589 SDContainer sc = in.getSDContainer(i);
[144]590//
[169]591 Array<Float> tSys(sc.getTsys()); // Get it out before sc changes shape
[144]592
[169]593// Bin up spectrum
[144]594
[169]595 MaskedArray<Float> marr(in.rowAsMaskedArray(i));
596 MaskedArray<Float> marrout;
[221]597 LatticeUtilities::bin(marrout, marr, asap::ChanAxis, width);
[144]598
[169]599// Put back the binned data and flags
[144]600
[169]601 IPosition ip2 = marrout.shape();
602 sc.resize(ip2);
[146]603//
[185]604 putDataInSDC(sc, marrout.getArray(), marrout.getMask());
[146]605
[169]606// Bin up Tsys.
[146]607
[169]608 Array<Bool> allGood(tSys.shape(),True);
609 MaskedArray<Float> tSysIn(tSys, allGood, True);
[146]610//
[169]611 MaskedArray<Float> tSysOut;
[221]612 LatticeUtilities::bin(tSysOut, tSysIn, asap::ChanAxis, width);
[169]613 sc.putTsys(tSysOut.getArray());
[146]614//
[169]615 pTabOut->putSDContainer(sc);
616 }
617 return pTabOut;
[146]618}
619
[299]620SDMemTable* SDMath::resample (const SDMemTable& in, const String& methodStr,
621 Float width) const
622//
623// Should add the possibility of width being specified in km/s. This means
624// that for each freqID (SpectralCoordinate) we will need to convert to an
625// average channel width (say at the reference pixel). Then we would need
626// to be careful to make sure each spectrum (of different freqID)
627// is the same length.
628//
629{
630 Bool doVel = False;
[309]631 if (doVel) {
632 for (uInt j=0; j<in.nCoordinates(); ++j) {
633 SpectralCoordinate sC = in.getSpectralCoordinate(j);
634 }
635 }
[299]636
637// Interpolation method
638
[317]639 InterpolateArray1D<Double,Float>::InterpolationMethod interp;
640 convertInterpString(interp, methodStr);
641 Int interpMethod(interp);
[299]642
643// Make output table
644
645 SDMemTable* pTabOut = new SDMemTable(in, True);
646
647// Resample SpectralCoordinates (one per freqID)
648
649 const uInt nCoord = in.nCoordinates();
650 Vector<Float> offset(1,0.0);
651 Vector<Float> factors(1,1.0/width);
652 Vector<Int> newShape;
653 for (uInt j=0; j<in.nCoordinates(); ++j) {
654 CoordinateSystem cSys;
655 cSys.addCoordinate(in.getSpectralCoordinate(j));
656 CoordinateSystem cSys2 = cSys.subImage(offset, factors, newShape);
657 SpectralCoordinate sC = cSys2.spectralCoordinate(0);
658//
659 pTabOut->setCoordinate(sC, j);
660 }
661
662// Get header
663
664 SDHeader sh = in.getSDHeader();
665
666// Generate resampling vectors
667
668 const uInt nChanIn = sh.nchan;
669 Vector<Float> xIn(nChanIn);
670 indgen(xIn);
671//
672 Int fac = Int(nChanIn/width);
673 Vector<Float> xOut(fac+10); // 10 to be safe - resize later
674 uInt i = 0;
675 Float x = 0.0;
676 Bool more = True;
677 while (more) {
678 xOut(i) = x;
679//
680 i++;
681 x += width;
682 if (x>nChanIn-1) more = False;
683 }
684 const uInt nChanOut = i;
685 xOut.resize(nChanOut,True);
686//
687 IPosition shapeIn(in.rowAsMaskedArray(0).shape());
688 sh.nchan = nChanOut;
689 pTabOut->putSDHeader(sh);
690
691// Loop over rows and resample along channel axis
692
693 Array<Float> valuesOut;
694 Array<Bool> maskOut;
695 Array<Float> tSysOut;
696 Array<Bool> tSysMaskIn(shapeIn,True);
697 Array<Bool> tSysMaskOut;
698 for (uInt i=0; i < in.nRow(); ++i) {
699
700// Get container
701
702 SDContainer sc = in.getSDContainer(i);
703
704// Get data and Tsys
705
706 const Array<Float>& tSysIn = sc.getTsys();
707 const MaskedArray<Float>& dataIn(in.rowAsMaskedArray(i));
708 Array<Float> valuesIn = dataIn.getArray();
709 Array<Bool> maskIn = dataIn.getMask();
710
711// Interpolate data
712
713 InterpolateArray1D<Float,Float>::interpolate(valuesOut, maskOut, xOut,
714 xIn, valuesIn, maskIn,
715 interpMethod, True, True);
716 sc.resize(valuesOut.shape());
717 putDataInSDC(sc, valuesOut, maskOut);
718
719// Interpolate TSys
720
721 InterpolateArray1D<Float,Float>::interpolate(tSysOut, tSysMaskOut, xOut,
722 xIn, tSysIn, tSysMaskIn,
723 interpMethod, True, True);
724 sc.putTsys(tSysOut);
725
726// Put container in output
727
728 pTabOut->putSDContainer(sc);
729 }
730//
731 return pTabOut;
732}
733
[248]734SDMemTable* SDMath::unaryOperate(const SDMemTable& in, Float val, Bool doAll,
[294]735 uInt what, Bool doTSys) const
[152]736//
737// what = 0 Multiply
738// 1 Add
[146]739{
[152]740 SDMemTable* pOut = new SDMemTable(in,False);
741 const Table& tOut = pOut->table();
[294]742 ArrayColumn<Float> specCol(tOut,"SPECTRA");
743 ArrayColumn<Float> tSysCol(tOut,"TSYS");
744 Array<Float> tSysArr;
[146]745//
[152]746 if (doAll) {
747 for (uInt i=0; i < tOut.nrow(); i++) {
[294]748
749// Modify data
750
[270]751 MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
[152]752 if (what==0) {
[270]753 dataIn *= val;
[152]754 } else if (what==1) {
[270]755 dataIn += val;
[152]756 }
[294]757 specCol.put(i, dataIn.getArray());
758
759// Modify Tsys
760
761 if (doTSys) {
762 tSysCol.get(i, tSysArr);
763 if (what==0) {
764 tSysArr *= val;
765 } else if (what==1) {
766 tSysArr += val;
767 }
768 tSysCol.put(i, tSysArr);
769 }
[152]770 }
771 } else {
772
773// Get cursor location
774
775 IPosition start, end;
[185]776 getCursorLocation(start, end, in);
[152]777//
778 for (uInt i=0; i < tOut.nrow(); i++) {
[294]779
780// Modify data
781
[152]782 MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
[270]783 MaskedArray<Float> dataIn2 = dataIn(start,end); // Reference
[152]784 if (what==0) {
[270]785 dataIn2 *= val;
[152]786 } else if (what==1) {
[270]787 dataIn2 += val;
[152]788 }
[294]789 specCol.put(i, dataIn.getArray());
790
791// Modify Tsys
792
793 if (doTSys) {
794 tSysCol.get(i, tSysArr);
795 Array<Float> tSysArr2 = tSysArr(start,end); // Reference
796 if (what==0) {
797 tSysArr2 *= val;
798 } else if (what==1) {
799 tSysArr2 += val;
800 }
801 tSysCol.put(i, tSysArr);
802 }
[152]803 }
804 }
805//
[146]806 return pOut;
807}
808
809
[152]810
[315]811SDMemTable* SDMath::averagePol(const SDMemTable& in, const Vector<Bool>& mask,
812 const String& weightStr) const
[152]813//
[165]814// Average all polarizations together, weighted by variance
815//
816{
[315]817 WeightType wtType = NONE;
818 convertWeightString(wtType, weightStr);
[165]819
820 const uInt nRows = in.nRow();
821
822// Create output Table and reshape number of polarizations
823
824 Bool clear=True;
825 SDMemTable* pTabOut = new SDMemTable(in, clear);
826 SDHeader header = pTabOut->getSDHeader();
827 header.npol = 1;
828 pTabOut->putSDHeader(header);
829
830// Shape of input and output data
831
832 const IPosition& shapeIn = in.rowAsMaskedArray(0u, False).shape();
833 IPosition shapeOut(shapeIn);
[262]834 shapeOut(asap::PolAxis) = 1; // Average all polarizations
[315]835 if (shapeIn(asap::PolAxis)==1) {
836 throw(AipsError("The input has only one polarisation"));
837 }
[165]838//
[262]839 const uInt nChan = shapeIn(asap::ChanAxis);
[165]840 const IPosition vecShapeOut(4,1,1,1,nChan); // A multi-dim form of a Vector shape
841 IPosition start(4), end(4);
842
843// Output arrays
844
845 Array<Float> outData(shapeOut, 0.0);
846 Array<Bool> outMask(shapeOut, True);
[262]847 const IPosition axes(2, asap::PolAxis, asap::ChanAxis); // pol-channel plane
[165]848//
[262]849 const Bool useMask = (mask.nelements() == shapeIn(asap::ChanAxis));
[165]850
851// Loop over rows
852
853 for (uInt iRow=0; iRow<nRows; iRow++) {
854
855// Get data for this row
856
857 MaskedArray<Float> marr(in.rowAsMaskedArray(iRow));
858 Array<Float>& arr = marr.getRWArray();
859 const Array<Bool>& barr = marr.getMask();
860
861// Make iterators to iterate by pol-channel planes
862
863 ReadOnlyArrayIterator<Float> itDataPlane(arr, axes);
864 ReadOnlyArrayIterator<Bool> itMaskPlane(barr, axes);
865
866// Accumulations
867
868 Float fac = 1.0;
869 Vector<Float> vecSum(nChan,0.0);
870
871// Iterate through data by pol-channel planes
872
873 while (!itDataPlane.pastEnd()) {
874
875// Iterate through plane by polarization and accumulate Vectors
876
877 Vector<Float> t1(nChan); t1 = 0.0;
878 Vector<Bool> t2(nChan); t2 = True;
879 MaskedArray<Float> vecSum(t1,t2);
[315]880 Float norm = 0.0;
[165]881 {
882 ReadOnlyVectorIterator<Float> itDataVec(itDataPlane.array(), 1);
883 ReadOnlyVectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
884 while (!itDataVec.pastEnd()) {
885
[315]886// Create MA of data & mask (optionally including OTF mask) and get variance for this spectrum
[165]887
888 if (useMask) {
889 const MaskedArray<Float> spec(itDataVec.vector(),mask&&itMaskVec.vector());
[315]890 if (wtType==VAR) fac = 1.0 / variance(spec);
[165]891 } else {
892 const MaskedArray<Float> spec(itDataVec.vector(),itMaskVec.vector());
[315]893 if (wtType==VAR) fac = 1.0 / variance(spec);
[165]894 }
895
896// Normalize spectrum (without OTF mask) and accumulate
897
898 const MaskedArray<Float> spec(fac*itDataVec.vector(), itMaskVec.vector());
899 vecSum += spec;
[315]900 norm += fac;
[165]901
902// Next
903
904 itDataVec.next();
905 itMaskVec.next();
906 }
907 }
908
909// Normalize summed spectrum
910
[315]911 vecSum /= norm;
[165]912
913// FInd position in input data array. We are iterating by pol-channel
914// plane so all that will change is beam and IF and that's what we want.
915
916 IPosition pos = itDataPlane.pos();
917
918// Write out data. This is a bit messy. We have to reform the Vector
919// accumulator into an Array of shape (1,1,1,nChan)
920
921 start = pos;
922 end = pos;
[262]923 end(asap::ChanAxis) = nChan-1;
[165]924 outData(start,end) = vecSum.getArray().reform(vecShapeOut);
925 outMask(start,end) = vecSum.getMask().reform(vecShapeOut);
926
927// Step to next beam/IF combination
928
929 itDataPlane.next();
930 itMaskPlane.next();
931 }
932
933// Generate output container and write it to output table
934
935 SDContainer sc = in.getSDContainer();
936 sc.resize(shapeOut);
937//
[185]938 putDataInSDC(sc, outData, outMask);
[165]939 pTabOut->putSDContainer(sc);
940 }
[304]941
942// Set polarization cursor to 0
943
944 pTabOut->setPol(0);
[165]945//
946 return pTabOut;
947}
[167]948
[169]949
[185]950SDMemTable* SDMath::smooth(const SDMemTable& in,
951 const casa::String& kernelType,
[234]952 casa::Float width, Bool doAll) const
[299]953//
954// Should smooth TSys as well
955//
[177]956{
[169]957
[177]958// Number of channels
[169]959
[177]960 SDHeader sh = in.getSDHeader();
961 const uInt nChan = sh.nchan;
962
963// Generate Kernel
964
[185]965 VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernelType);
[177]966 Vector<Float> kernel = VectorKernel::make(type, width, nChan, True, False);
967
968// Generate Convolver
969
970 IPosition shape(1,nChan);
971 Convolver<Float> conv(kernel, shape);
972
973// New Table
974
975 SDMemTable* pTabOut = new SDMemTable(in,True);
976
977// Get cursor location
978
979 IPosition start, end;
[185]980 getCursorLocation(start, end, in);
[177]981//
982 IPosition shapeOut(4,1);
983
984// Output Vectors
985
986 Vector<Float> valuesOut(nChan);
987 Vector<Bool> maskOut(nChan);
988
989// Loop over rows in Table
990
991 for (uInt ri=0; ri < in.nRow(); ++ri) {
992
993// Get copy of data
994
995 const MaskedArray<Float>& dataIn(in.rowAsMaskedArray(ri));
[262]996 AlwaysAssert(dataIn.shape()(asap::ChanAxis)==nChan, AipsError);
[177]997//
998 Array<Float> valuesIn = dataIn.getArray();
999 Array<Bool> maskIn = dataIn.getMask();
1000
1001// Branch depending on whether we smooth all locations or just
1002// those pointed at by the current selection cursor
1003
1004 if (doAll) {
[299]1005 VectorIterator<Float> itValues(valuesIn, asap::ChanAxis);
1006 VectorIterator<Bool> itMask(maskIn, asap::ChanAxis);
[177]1007 while (!itValues.pastEnd()) {
1008
1009// Smooth
1010 if (kernelType==VectorKernel::HANNING) {
1011 mathutil::hanning(valuesOut, maskOut, itValues.vector(), itMask.vector());
1012 itMask.vector() = maskOut;
1013 } else {
1014 mathutil::replaceMaskByZero(itValues.vector(), itMask.vector());
1015 conv.linearConv(valuesOut, itValues.vector());
1016 }
1017//
1018 itValues.vector() = valuesOut;
1019//
1020 itValues.next();
1021 itMask.next();
1022 }
1023 } else {
1024
1025// Set multi-dim Vector shape
1026
[299]1027 shapeOut(asap::ChanAxis) = valuesIn.shape()(asap::ChanAxis);
[177]1028
1029// Stuff about with shapes so that we don't have conformance run-time errors
1030
1031 Vector<Float> valuesIn2 = valuesIn(start,end).nonDegenerate();
1032 Vector<Bool> maskIn2 = maskIn(start,end).nonDegenerate();
1033
1034// Smooth
1035
1036 if (kernelType==VectorKernel::HANNING) {
1037 mathutil::hanning(valuesOut, maskOut, valuesIn2, maskIn2);
1038 maskIn(start,end) = maskOut.reform(shapeOut);
1039 } else {
1040 mathutil::replaceMaskByZero(valuesIn2, maskIn2);
1041 conv.linearConv(valuesOut, valuesIn2);
1042 }
1043//
1044 valuesIn(start,end) = valuesOut.reform(shapeOut);
1045 }
1046
1047// Create and put back
1048
1049 SDContainer sc = in.getSDContainer(ri);
[185]1050 putDataInSDC(sc, valuesIn, maskIn);
[177]1051//
1052 pTabOut->putSDContainer(sc);
1053 }
1054//
1055 return pTabOut;
1056}
1057
1058
[262]1059
[234]1060SDMemTable* SDMath::convertFlux (const SDMemTable& in, Float a, Float eta, Bool doAll) const
[221]1061//
1062// As it is, this function could be implemented with 'simpleOperate'
1063// However, I anticipate that eventually we will look the conversion
1064// values up in a Table and apply them in a frequency dependent way,
1065// so I have implemented it fully here
1066//
1067{
1068 SDHeader sh = in.getSDHeader();
1069 SDMemTable* pTabOut = new SDMemTable(in, True);
[177]1070
[221]1071// FInd out how to convert values into Jy and K (e.g. units might be mJy or mK)
1072// Also automatically find out what we are converting to according to the
1073// flux unit
[177]1074
[221]1075 Unit fluxUnit(sh.fluxunit);
1076 Unit K(String("K"));
1077 Unit JY(String("Jy"));
1078//
1079 Bool toKelvin = True;
1080 Double inFac = 1.0;
1081 if (fluxUnit==JY) {
1082 cerr << "Converting to K" << endl;
1083//
1084 Quantum<Double> t(1.0,fluxUnit);
1085 Quantum<Double> t2 = t.get(JY);
1086 inFac = (t2 / t).getValue();
1087//
1088 toKelvin = True;
1089 sh.fluxunit = "K";
1090 } else if (fluxUnit==K) {
1091 cerr << "Converting to Jy" << endl;
1092//
1093 Quantum<Double> t(1.0,fluxUnit);
1094 Quantum<Double> t2 = t.get(K);
1095 inFac = (t2 / t).getValue();
1096//
1097 toKelvin = False;
1098 sh.fluxunit = "Jy";
1099 } else {
[248]1100 throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
[221]1101 }
1102 pTabOut->putSDHeader(sh);
[177]1103
[221]1104// Compute conversion factor. 'a' and 'eta' are really frequency, time and
1105// telescope dependent and should be looked// up in a table
1106
[234]1107 Float factor = 2.0 * inFac * 1.0e-7 * 1.0e26 *
1108 QC::k.getValue(Unit(String("erg/K"))) / a / eta;
[221]1109 if (toKelvin) {
1110 factor = 1.0 / factor;
1111 }
1112 cerr << "Applying conversion factor = " << factor << endl;
1113
[270]1114// Generate correction vector. Apply same factor regardless
1115// of beam/pol/IF. This will need to change somewhen.
[221]1116
[270]1117 Vector<Float> factors(in.nRow(), factor);
[221]1118
[270]1119// Correct
[221]1120
[270]1121 correctFromVector (pTabOut, in, doAll, factors);
[221]1122//
1123 return pTabOut;
1124}
1125
1126
[234]1127SDMemTable* SDMath::gainElevation (const SDMemTable& in, const Vector<Float>& coeffs,
1128 const String& fileName,
1129 const String& methodStr, Bool doAll) const
[227]1130{
[234]1131
1132// Get header and clone output table
1133
[227]1134 SDHeader sh = in.getSDHeader();
1135 SDMemTable* pTabOut = new SDMemTable(in, True);
1136
[234]1137// Get elevation data from SDMemTable and convert to degrees
[227]1138
1139 const Table& tab = in.table();
1140 ROScalarColumn<Float> elev(tab, "ELEVATION");
[234]1141 Vector<Float> x = elev.getColumn();
1142 x *= Float(180 / C::pi);
[227]1143//
[234]1144 const uInt nC = coeffs.nelements();
1145 if (fileName.length()>0 && nC>0) {
[248]1146 throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
[234]1147 }
1148
1149// Correct
1150
1151 if (nC>0 || fileName.length()==0) {
1152
1153// Find instrument
1154
1155 Bool throwIt = True;
1156 Instrument inst = SDMemTable::convertInstrument (sh.antennaname, throwIt);
1157
1158// Set polynomial
1159
1160 Polynomial<Float>* pPoly = 0;
1161 Vector<Float> coeff;
1162 String msg;
1163 if (nC>0) {
1164 pPoly = new Polynomial<Float>(nC);
1165 coeff = coeffs;
1166 msg = String("user");
1167 } else {
[292]1168 if (inst==ATPKSMB) {
1169 } else if (inst==ATPKSHOH) {
[234]1170 } else if (inst==TIDBINBILLA) {
1171 pPoly = new Polynomial<Float>(3);
1172 coeff.resize(3);
1173 coeff(0) = 3.58788e-1;
1174 coeff(1) = 2.87243e-2;
1175 coeff(2) = -3.219093e-4;
[292]1176 } else if (inst==ATMOPRA) {
1177 } else {
[234]1178 }
1179 msg = String("built in");
1180 }
[227]1181//
[234]1182 if (coeff.nelements()>0) {
1183 pPoly->setCoefficients(coeff);
1184 } else {
[248]1185 throw(AipsError("There is no known gain-el polynomial known for this instrument"));
[234]1186 }
1187//
1188 cerr << "Making polynomial correction with " << msg << " coefficients" << endl;
1189 const uInt nRow = in.nRow();
1190 Vector<Float> factor(nRow);
1191 for (uInt i=0; i<nRow; i++) {
1192 factor[i] = (*pPoly)(x[i]);
1193 }
1194 delete pPoly;
1195//
1196 correctFromVector (pTabOut, in, doAll, factor);
1197 } else {
1198
1199// Indicate which columns to read from ascii file
1200
1201 String col0("ELEVATION");
1202 String col1("FACTOR");
1203
1204// Read and correct
1205
1206 cerr << "Making correction from ascii Table" << endl;
1207 correctFromAsciiTable (pTabOut, in, fileName, col0, col1,
1208 methodStr, doAll, x);
1209 }
1210//
1211 return pTabOut;
[230]1212}
[227]1213
[230]1214
[227]1215
[234]1216SDMemTable* SDMath::opacity (const SDMemTable& in, Float tau, Bool doAll) const
1217{
[227]1218
[234]1219// Get header and clone output table
[227]1220
[234]1221 SDHeader sh = in.getSDHeader();
1222 SDMemTable* pTabOut = new SDMemTable(in, True);
1223
1224// Get elevation data from SDMemTable and convert to degrees
1225
1226 const Table& tab = in.table();
1227 ROScalarColumn<Float> elev(tab, "ELEVATION");
1228 Vector<Float> zDist = elev.getColumn();
1229 zDist = Float(C::pi_2) - zDist;
1230
1231// Generate correction factor
1232
1233 const uInt nRow = in.nRow();
1234 Vector<Float> factor(nRow);
1235 Vector<Float> factor2(nRow);
1236 for (uInt i=0; i<nRow; i++) {
1237 factor[i] = exp(tau)/cos(zDist[i]);
1238 }
1239
1240// Correct
1241
1242 correctFromVector (pTabOut, in, doAll, factor);
1243//
1244 return pTabOut;
1245}
1246
1247
1248
1249
[169]1250// 'private' functions
1251
[309]1252
1253SDMemTable* SDMath::frequencyAlign (const SDMemTable& in,
1254 MFrequency::Types freqSystem,
[317]1255 const String& refTime, const String& methodStr) const
[267]1256{
1257// Get Header
1258
1259 SDHeader sh = in.getSDHeader();
1260 const uInt nChan = sh.nchan;
1261 const uInt nRows = in.nRow();
1262
1263// Get Table reference
1264
1265 const Table& tabIn = in.table();
1266
1267// Get Columns from Table
1268
[294]1269 ROScalarColumn<Double> mjdCol(tabIn, "TIME");
1270 ROScalarColumn<String> srcCol(tabIn, "SRCNAME");
1271 ROArrayColumn<uInt> fqIDCol(tabIn, "FREQID");
[267]1272//
[294]1273 Vector<Double> times = mjdCol.getColumn();
1274 Vector<String> srcNames = srcCol.getColumn();
1275 Vector<uInt> freqID;
[267]1276
1277// Generate Source table
1278
1279 Vector<String> srcTab;
1280 Vector<uInt> srcIdx, firstRow;
1281 generateSourceTable (srcTab, srcIdx, firstRow, srcNames);
1282 const uInt nSrcTab = srcTab.nelements();
1283 cerr << "Found " << srcTab.nelements() << " sources to align " << endl;
1284
[294]1285// Get reference Epoch to time of first row or given String
[267]1286
1287 Unit DAY(String("d"));
[272]1288 MEpoch::Ref epochRef(in.getTimeReference());
1289 MEpoch refEpoch;
1290 if (refTime.length()>0) {
1291 refEpoch = epochFromString(refTime, in.getTimeReference());
1292 } else {
[288]1293 refEpoch = in.getEpoch(0);
[272]1294 }
[309]1295 cerr << "Aligning at reference Epoch " << formatEpoch(refEpoch) <<
1296 " in frame " << MFrequency::showType(freqSystem) << endl;
[267]1297
[294]1298// Get Reference Position
[267]1299
[288]1300 MPosition refPos = in.getAntennaPosition();
[267]1301
1302// Get Frequency Table
1303
1304 SDFrequencyTable fTab = in.getSDFreqTable();
1305 const uInt nFreqIDs = fTab.length();
1306
[309]1307// Create FrequencyAligner Block. One VA for each possible
[267]1308// source/freqID combination
1309
[309]1310 PtrBlock<FrequencyAligner<Float>* > a(nFreqIDs*nSrcTab);
1311 generateFrequencyAligners (a, in, nChan, nFreqIDs, nSrcTab, firstRow,
1312 freqSystem, refPos, refEpoch);
[267]1313
[317]1314// Interpolation method
1315
1316 InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1317 convertInterpString(interp, methodStr);
1318
[267]1319// New output Table
1320
1321 SDMemTable* pTabOut = new SDMemTable(in,True);
1322
1323// Loop over rows in Table
1324
[294]1325 const IPosition polChanAxes(2, asap::PolAxis, asap::ChanAxis);
[317]1326
[294]1327 Bool extrapolate=False;
1328 Bool useCachedAbcissa = False;
1329 Bool first = True;
1330 Bool ok;
1331 Vector<Float> yOut;
1332 Vector<Bool> maskOut;
[309]1333 uInt ifIdx, faIdx;
[267]1334//
[294]1335 for (uInt iRow=0; iRow<nRows; ++iRow) {
1336 if (iRow%10==0) {
1337 cerr << "Processing row " << iRow << endl;
1338 }
[267]1339
1340// Get EPoch
1341
[294]1342 Quantum<Double> tQ2(times[iRow],DAY);
1343 MVEpoch mv2(tQ2);
1344 MEpoch epoch(mv2, epochRef);
[267]1345
1346// Get FreqID vector. One freqID per IF
1347
[294]1348 fqIDCol.get(iRow, freqID);
[267]1349
1350// Get copy of data
1351
[294]1352 const MaskedArray<Float>& mArrIn(in.rowAsMaskedArray(iRow));
1353 Array<Float> values = mArrIn.getArray();
1354 Array<Bool> mask = mArrIn.getMask();
[267]1355
1356// cerr << "values in = " << values(IPosition(4,0,0,0,0),IPosition(4,0,0,0,9)) << endl;
1357
[309]1358// For each row, the Frequency abcissa will be the same regardless
[267]1359// of polarization. For all other axes (IF and BEAM) the abcissa
1360// will change. So we iterate through the data by pol-chan planes
1361// to mimimize the work. At this point, I think the Direction
1362// is stored as the same for each beam. DOn't know where the
1363// offsets are or what to do about them right now. For now
1364// all beams get same position and velocoity abcissa.
1365
[294]1366 ArrayIterator<Float> itValuesPlane(values, polChanAxes);
1367 ArrayIterator<Bool> itMaskPlane(mask, polChanAxes);
1368 while (!itValuesPlane.pastEnd()) {
[267]1369
[309]1370// Find the IF index and then the FA PtrBlock index
[267]1371
[294]1372 const IPosition& pos = itValuesPlane.pos();
1373 ifIdx = pos(asap::IFAxis);
[309]1374 faIdx = (srcIdx[iRow]*nFreqIDs) + freqID[ifIdx];
[267]1375//
[294]1376 VectorIterator<Float> itValuesVec(itValuesPlane.array(), 1);
1377 VectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
[267]1378//
[294]1379 first = True;
1380 useCachedAbcissa=False;
1381 while (!itValuesVec.pastEnd()) {
[309]1382 ok = a[faIdx]->align (yOut, maskOut, itValuesVec.vector(),
[317]1383 itMaskVec.vector(), epoch, useCachedAbcissa,
1384 interp, extrapolate);
[294]1385 itValuesVec.vector() = yOut;
1386 itMaskVec.vector() = maskOut;
[267]1387//
[294]1388 itValuesVec.next();
1389 itMaskVec.next();
[267]1390//
[294]1391 if (first) {
1392 useCachedAbcissa = True;
1393 first = False;
1394 }
1395 }
[267]1396//
1397 itValuesPlane.next();
1398 itMaskPlane.next();
[294]1399 }
[267]1400
1401// cerr << "values out = " << values(IPosition(4,0,0,0,0),IPosition(4,0,0,0,9)) << endl;
1402
1403// Create and put back
1404
1405 SDContainer sc = in.getSDContainer(iRow);
1406 putDataInSDC(sc, values, mask);
1407//
1408 pTabOut->putSDContainer(sc);
[294]1409 }
[267]1410
[309]1411
1412// Write out correct frequency table information for output.
1413// CLone from input and overwrite
1414
1415 SDFrequencyTable freqTab = in.getSDFreqTable();
1416 freqTab.setLength(0);
1417
1418// Note that we don't have anyway to hold frequency table information
1419// in the SDMemTable which is source dependent. Each FrequencyAligner
1420// is generated for an freqID/Source combination. Don't know what to
1421// do about this apart from to pick the aligned SC from the first source
1422// at the moment. ASAP really needs to handle data description id
1423// like in aips++ which is a combination of source and freqid. Otherwise
1424// all else I can do in this function is disallow multiple sources
1425
1426 Bool linear=True;
1427 Vector<String> units(1);
1428 units = String("Hz");
1429 for (uInt fqID=0; fqID<nFreqIDs; fqID++) {
1430 for (uInt iSrc=0; iSrc<nSrcTab; iSrc++) {
1431 uInt idx = (iSrc*nFreqIDs) + fqID;
1432
1433// Get Aligned SC in Hz
1434
1435 if (iSrc==0) {
1436 SpectralCoordinate sC = a[idx]->alignedSpectralCoordinate(linear);
1437 sC.setWorldAxisUnits(units);
1438
1439// Write out frequency table information to SDMemTable
1440
1441 Int idx = freqTab.addFrequency(sC.referencePixel()[0],
1442 sC.referenceValue()[0],
1443 sC.increment()[0]);
1444 }
1445 }
1446 }
1447 pTabOut->putSDFreqTable(freqTab);
1448
1449// Now we must set the base and extra frames to the
1450// input frame
1451
1452 std::vector<string> info = pTabOut->getCoordInfo();
1453 info[1] = MFrequency::showType(freqSystem); // Conversion frame
1454 info[3] = info[1]; // Base frame
1455 pTabOut->setCoordInfo(info);
1456
[267]1457// Clean up PointerBlock
1458
[309]1459 for (uInt i=0; i<a.nelements(); i++) delete a[i];
[267]1460//
[309]1461 return pTabOut;
[267]1462}
1463
1464
[185]1465void SDMath::fillSDC(SDContainer& sc,
1466 const Array<Bool>& mask,
1467 const Array<Float>& data,
1468 const Array<Float>& tSys,
1469 Int scanID, Double timeStamp,
1470 Double interval, const String& sourceName,
[227]1471 const Vector<uInt>& freqID) const
[167]1472{
[169]1473// Data and mask
[167]1474
[185]1475 putDataInSDC(sc, data, mask);
[167]1476
[169]1477// TSys
1478
1479 sc.putTsys(tSys);
1480
1481// Time things
1482
1483 sc.timestamp = timeStamp;
1484 sc.interval = interval;
1485 sc.scanid = scanID;
[167]1486//
[169]1487 sc.sourcename = sourceName;
1488 sc.putFreqMap(freqID);
1489}
[167]1490
[185]1491void SDMath::normalize(MaskedArray<Float>& sum,
[169]1492 const Array<Float>& sumSq,
1493 const Array<Float>& nPts,
1494 WeightType wtType, Int axis,
[227]1495 Int nAxesSub) const
[169]1496{
1497 IPosition pos2(nAxesSub,0);
1498//
1499 if (wtType==NONE) {
[167]1500
[169]1501// We just average by the number of points accumulated.
1502// We need to make a MA out of nPts so that no divide by
1503// zeros occur
[167]1504
[169]1505 MaskedArray<Float> t(nPts, (nPts>Float(0.0)));
1506 sum /= t;
1507 } else if (wtType==VAR) {
[167]1508
[169]1509// Normalize each spectrum by sum(1/var) where the variance
1510// is worked out for each spectrum
1511
1512 Array<Float>& data = sum.getRWArray();
1513 VectorIterator<Float> itData(data, axis);
1514 while (!itData.pastEnd()) {
1515 pos2 = itData.pos().getFirst(nAxesSub);
1516 itData.vector() /= sumSq(pos2);
1517 itData.next();
1518 }
1519 } else if (wtType==TSYS) {
1520 }
1521}
1522
1523
[185]1524void SDMath::accumulate(Double& timeSum, Double& intSum, Int& nAccum,
1525 MaskedArray<Float>& sum, Array<Float>& sumSq,
1526 Array<Float>& nPts, Array<Float>& tSysSum,
1527 const Array<Float>& tSys, const Array<Float>& nInc,
1528 const Vector<Bool>& mask, Double time, Double interval,
1529 const Block<CountedPtr<SDMemTable> >& in,
1530 uInt iTab, uInt iRow, uInt axis,
1531 uInt nAxesSub, Bool useMask,
[227]1532 WeightType wtType) const
[169]1533{
1534
1535// Get data
1536
1537 MaskedArray<Float> dataIn(in[iTab]->rowAsMaskedArray(iRow));
1538 Array<Float>& valuesIn = dataIn.getRWArray(); // writable reference
1539 const Array<Bool>& maskIn = dataIn.getMask(); // RO reference
[167]1540//
[169]1541 if (wtType==NONE) {
1542 const MaskedArray<Float> n(nInc,dataIn.getMask());
1543 nPts += n; // Only accumulates where mask==T
1544 } else if (wtType==VAR) {
[167]1545
[169]1546// We are going to average the data, weighted by the noise for each pol, beam and IF.
1547// So therefore we need to iterate through by spectrum (axis 3)
[167]1548
[169]1549 VectorIterator<Float> itData(valuesIn, axis);
1550 ReadOnlyVectorIterator<Bool> itMask(maskIn, axis);
1551 Float fac = 1.0;
1552 IPosition pos(nAxesSub,0);
1553//
1554 while (!itData.pastEnd()) {
[167]1555
[169]1556// Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor
[167]1557
[169]1558 if (useMask) {
1559 MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());
1560 fac = 1.0/variance(tmp);
1561 } else {
1562 MaskedArray<Float> tmp(itData.vector(),itMask.vector());
1563 fac = 1.0/variance(tmp);
1564 }
1565
1566// Scale data
1567
1568 itData.vector() *= fac; // Writes back into 'dataIn'
[167]1569//
[169]1570// Accumulate variance per if/pol/beam averaged over spectrum
1571// This method to get pos2 from itData.pos() is only valid
1572// because the spectral axis is the last one (so we can just
1573// copy the first nAXesSub positions out)
[167]1574
[169]1575 pos = itData.pos().getFirst(nAxesSub);
1576 sumSq(pos) += fac;
1577//
1578 itData.next();
1579 itMask.next();
1580 }
1581 } else if (wtType==TSYS) {
1582 }
[167]1583
[169]1584// Accumulate sum of (possibly scaled) data
1585
1586 sum += dataIn;
1587
1588// Accumulate Tsys, time, and interval
1589
1590 tSysSum += tSys;
1591 timeSum += time;
1592 intSum += interval;
1593 nAccum += 1;
1594}
1595
1596
1597
1598
[185]1599void SDMath::getCursorLocation(IPosition& start, IPosition& end,
[227]1600 const SDMemTable& in) const
[169]1601{
1602 const uInt nDim = 4;
1603 const uInt i = in.getBeam();
1604 const uInt j = in.getIF();
1605 const uInt k = in.getPol();
1606 const uInt n = in.nChan();
[167]1607//
[169]1608 start.resize(nDim);
1609 start(0) = i;
1610 start(1) = j;
1611 start(2) = k;
1612 start(3) = 0;
[167]1613//
[169]1614 end.resize(nDim);
1615 end(0) = i;
1616 end(1) = j;
1617 end(2) = k;
1618 end(3) = n-1;
1619}
1620
1621
[227]1622void SDMath::convertWeightString(WeightType& wtType, const String& weightStr) const
[169]1623{
1624 String tStr(weightStr);
1625 tStr.upcase();
1626 if (tStr.contains(String("NONE"))) {
1627 wtType = NONE;
1628 } else if (tStr.contains(String("VAR"))) {
1629 wtType = VAR;
1630 } else if (tStr.contains(String("TSYS"))) {
1631 wtType = TSYS;
[185]1632 throw(AipsError("T_sys weighting not yet implemented"));
[169]1633 } else {
[185]1634 throw(AipsError("Unrecognized weighting type"));
[167]1635 }
1636}
1637
[317]1638
1639void SDMath::convertInterpString(casa::InterpolateArray1D<Double,Float>::InterpolationMethod& type,
1640 const casa::String& interp) const
[227]1641{
1642 String tStr(interp);
1643 tStr.upcase();
1644 if (tStr.contains(String("NEAR"))) {
[317]1645 type = InterpolateArray1D<Double,Float>::nearestNeighbour;
[227]1646 } else if (tStr.contains(String("LIN"))) {
[317]1647 type = InterpolateArray1D<Double,Float>::linear;
[227]1648 } else if (tStr.contains(String("CUB"))) {
[317]1649 type = InterpolateArray1D<Double,Float>::cubic;
[227]1650 } else if (tStr.contains(String("SPL"))) {
[317]1651 type = InterpolateArray1D<Double,Float>::spline;
[227]1652 } else {
1653 throw(AipsError("Unrecognized interpolation type"));
1654 }
1655}
1656
[185]1657void SDMath::putDataInSDC(SDContainer& sc, const Array<Float>& data,
[227]1658 const Array<Bool>& mask) const
[169]1659{
1660 sc.putSpectrum(data);
1661//
1662 Array<uChar> outflags(data.shape());
1663 convertArray(outflags,!mask);
1664 sc.putFlags(outflags);
1665}
[227]1666
1667Table SDMath::readAsciiFile (const String& fileName) const
1668{
[230]1669 String formatString;
1670 Table tbl = readAsciiTable (formatString, Table::Memory, fileName, "", "", False);
[227]1671 return tbl;
1672}
[230]1673
1674
[234]1675
1676void SDMath::correctFromAsciiTable(SDMemTable* pTabOut,
1677 const SDMemTable& in, const String& fileName,
1678 const String& col0, const String& col1,
1679 const String& methodStr, Bool doAll,
1680 const Vector<Float>& xOut) const
[230]1681{
1682
1683// Read gain-elevation ascii file data into a Table.
1684
[234]1685 Table geTable = readAsciiFile (fileName);
[230]1686//
[234]1687 correctFromTable (pTabOut, in, geTable, col0, col1, methodStr, doAll, xOut);
[230]1688}
1689
[234]1690void SDMath::correctFromTable(SDMemTable* pTabOut, const SDMemTable& in,
1691 const Table& tTable, const String& col0,
1692 const String& col1,
1693 const String& methodStr, Bool doAll,
1694 const Vector<Float>& xOut) const
[230]1695{
1696
1697// Get data from Table
1698
1699 ROScalarColumn<Float> geElCol(tTable, col0);
1700 ROScalarColumn<Float> geFacCol(tTable, col1);
1701 Vector<Float> xIn = geElCol.getColumn();
1702 Vector<Float> yIn = geFacCol.getColumn();
1703 Vector<Bool> maskIn(xIn.nelements(),True);
1704
1705// Interpolate (and extrapolate) with desired method
1706
[317]1707 InterpolateArray1D<Double,Float>::InterpolationMethod method;
[230]1708 convertInterpString(method, methodStr);
[317]1709 Int intMethod(method);
[230]1710//
1711 Vector<Float> yOut;
1712 Vector<Bool> maskOut;
1713 InterpolateArray1D<Float,Float>::interpolate(yOut, maskOut, xOut,
[317]1714 xIn, yIn, maskIn, intMethod,
[230]1715 True, True);
[234]1716// Apply
[230]1717
[234]1718 correctFromVector (pTabOut, in, doAll, yOut);
1719}
1720
1721
1722void SDMath::correctFromVector (SDMemTable* pTabOut, const SDMemTable& in,
1723 Bool doAll, const Vector<Float>& factor) const
1724{
[270]1725
[230]1726// For operations only on specified cursor location
1727
1728 IPosition start, end;
1729 getCursorLocation(start, end, in);
1730
[270]1731// Loop over rows and apply correction factor
[230]1732
1733 const uInt axis = asap::ChanAxis;
1734 for (uInt i=0; i < in.nRow(); ++i) {
1735
1736// Get data
1737
1738 MaskedArray<Float> dataIn(in.rowAsMaskedArray(i));
1739
1740// Apply factor
1741
1742 if (doAll) {
[270]1743 dataIn *= factor[i];
[230]1744 } else {
[270]1745 MaskedArray<Float> dataIn2 = dataIn(start,end); // reference
1746 dataIn2 *= factor[i];
[230]1747 }
1748
1749// Write out
1750
1751 SDContainer sc = in.getSDContainer(i);
[270]1752 putDataInSDC(sc, dataIn.getArray(), dataIn.getMask());
[230]1753//
1754 pTabOut->putSDContainer(sc);
1755 }
1756}
1757
[234]1758
[262]1759void SDMath::generateSourceTable (Vector<String>& srcTab,
1760 Vector<uInt>& srcIdx,
1761 Vector<uInt>& firstRow,
1762 const Vector<String>& srcNames) const
1763//
1764// This algorithm assumes that if there are multiple beams
1765// that the source names are diffent. Oterwise we would need
1766// to look atthe direction for each beam...
1767//
1768{
1769 const uInt nRow = srcNames.nelements();
1770 srcTab.resize(0);
1771 srcIdx.resize(nRow);
1772 firstRow.resize(0);
1773//
1774 uInt nSrc = 0;
1775 for (uInt i=0; i<nRow; i++) {
1776 String srcName = srcNames[i];
1777
1778// Do we have this source already ?
1779
1780 Int idx = -1;
1781 if (nSrc>0) {
1782 for (uInt j=0; j<nSrc; j++) {
1783 if (srcName==srcTab[j]) {
1784 idx = j;
1785 break;
1786 }
1787 }
1788 }
1789
1790// Add new entry if not found
1791
1792 if (idx==-1) {
1793 nSrc++;
1794 srcTab.resize(nSrc,True);
1795 srcTab(nSrc-1) = srcName;
1796 idx = nSrc-1;
1797//
1798 firstRow.resize(nSrc,True);
1799 firstRow(nSrc-1) = i; // First row for which this source occurs
1800 }
1801
1802// Set index for this row
1803
1804 srcIdx[i] = idx;
1805 }
1806}
[272]1807
1808MEpoch SDMath::epochFromString (const String& str, MEpoch::Types timeRef) const
1809{
1810 Quantum<Double> qt;
1811 if (MVTime::read(qt,str)) {
1812 MVEpoch mv(qt);
1813 MEpoch me(mv, timeRef);
1814 return me;
1815 } else {
1816 throw(AipsError("Invalid format for Epoch string"));
1817 }
1818}
1819
1820
1821String SDMath::formatEpoch(const MEpoch& epoch) const
1822{
1823 MVTime mvt(epoch.getValue());
1824 return mvt.string(MVTime::YMD) + String(" (") + epoch.getRefString() + String(")");
1825}
1826
[294]1827
[309]1828
1829void SDMath::generateFrequencyAligners (PtrBlock<FrequencyAligner<Float>* >& a,
[294]1830 const SDMemTable& in, uInt nChan,
1831 uInt nFreqIDs, uInt nSrcTab,
1832 const Vector<uInt>& firstRow,
[309]1833 MFrequency::Types system,
[294]1834 const MPosition& refPos,
1835 const MEpoch& refEpoch) const
1836{
1837 for (uInt fqID=0; fqID<nFreqIDs; fqID++) {
1838 SpectralCoordinate sC = in.getSpectralCoordinate(fqID);
1839 for (uInt iSrc=0; iSrc<nSrcTab; iSrc++) {
1840 MDirection refDir = in.getDirection(firstRow[iSrc]);
1841 uInt idx = (iSrc*nFreqIDs) + fqID;
[309]1842 a[idx] = new FrequencyAligner<Float>(sC, nChan, refEpoch, refDir, refPos, system);
[294]1843 }
1844 }
1845}
1846
[309]1847
Note: See TracBrowser for help on using the repository browser.