source: trunk/src/SDMath.cc@ 271

Last change on this file since 271 was 270, checked in by kil064, 21 years ago

use new MaskedArray(IPosition,IPOsition) slice operator
to simplyify some code. Also reuse function 'correctFromVector'
more to consolidate code

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