source: trunk/src/SDMath.cc @ 224

Last change on this file since 224 was 221, checked in by kil064, 19 years ago

add function 'convertFlux'

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