Changeset 144
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/SDMath.cc
r139 r144 64 64 //using namespace asap::SDMath; 65 65 66 CountedPtr<SDMemTable> SDMath::average(const CountedPtr<SDMemTable>& in) 67 // 68 // Average all rows in Table in time 69 // 70 { 71 Table t = in->table(); 72 ROArrayColumn<Float> tsys(t, "TSYS"); 73 ROScalarColumn<Double> mjd(t, "TIME"); 74 ROScalarColumn<String> srcn(t, "SRCNAME"); 75 ROScalarColumn<Double> integr(t, "INTERVAL"); 76 ROArrayColumn<uInt> freqidc(t, "FREQID"); 77 IPosition ip = in->rowAsMaskedArray(0).shape(); 78 Array<Float> outarr(ip); outarr =0.0; 79 Array<Float> narr(ip);narr = 0.0; 80 Array<Float> narrinc(ip);narrinc = 1.0; 81 82 Array<Float> tsarr(tsys.shape(0)); 83 Array<Float> outtsarr(tsys.shape(0)); 84 outtsarr =0.0; 85 tsys.get(0, tsarr);// this is probably unneccessary as tsys should 86 Double tme = 0.0; 87 Double inttime = 0.0; 88 89 // Loop over rows 90 91 for (uInt i=0; i < t.nrow(); i++) { 92 93 // Get data and accumulate sums 94 95 MaskedArray<Float> marr(in->rowAsMaskedArray(i)); 96 outarr += marr; 97 MaskedArray<Float> n(narrinc,marr.getMask()); 98 narr += n; 99 100 // Accumulkate Tsys 101 102 tsys.get(i, tsarr);// this is probably unneccessary as tsys should 103 outtsarr += tsarr; // be constant 104 Double tmp; 105 mjd.get(i,tmp); 106 tme += tmp;// average time 107 integr.get(i,tmp); 108 inttime += tmp; 109 } 110 111 // Average 112 113 MaskedArray<Float> nma(narr,(narr > Float(0))); 114 outarr /= nma; 115 116 // Create container and put 117 118 Array<Bool> outflagsb = !(nma.getMask()); 119 Array<uChar> outflags(outflagsb.shape()); 120 convertArray(outflags,outflagsb); 121 SDContainer sc = in->getSDContainer(); 122 Int n = t.nrow(); 123 outtsarr /= Float(n); 124 sc.timestamp = tme/Double(n); 125 sc.interval = inttime; 126 String tstr; srcn.getScalar(0,tstr);// get sourcename of "mid" point 127 sc.sourcename = tstr; 128 Vector<uInt> tvec; 129 freqidc.get(0,tvec); 130 sc.putFreqMap(tvec); 131 sc.putTsys(outtsarr); 132 sc.scanid = 0; 133 sc.putSpectrum(outarr); 134 sc.putFlags(outflags); 135 SDMemTable* sdmt = new SDMemTable(*in,True); 136 sdmt->putSDContainer(sc); 137 return CountedPtr<SDMemTable>(sdmt); 138 } 66 CountedPtr<SDMemTable> SDMath::average (const Block<CountedPtr<SDMemTable> >& in, 67 const Vector<Bool>& mask, bool scanAv, 68 const std::string& weightStr) 69 // 70 // Weighted averaging of spectra from one or more Tables. 71 // 72 { 73 weightType wtType = NONE; 74 String tStr(weightStr); 75 tStr.upcase(); 76 if (tStr.contains(String("NONE"))) { 77 wtType = NONE; 78 } else if (tStr.contains(String("VAR"))) { 79 wtType = VAR; 80 } else if (tStr.contains(String("TSYS"))) { 81 wtType = TSYS; 82 throw (AipsError("T_sys weighting not yet implemented")); 83 } else { 84 throw (AipsError("Unrecognized weighting type")); 85 } 86 87 // Create output Table by cloning from the first table 88 89 SDMemTable* pTabOut = new SDMemTable(*in[0],True); 90 91 // Setup 92 93 const uInt axis = 3; // Spectral axis 94 IPosition shp = in[0]->rowAsMaskedArray(0).shape(); // Must not change 95 Array<Float> arr(shp); 96 Array<Bool> barr(shp); 97 const Bool useMask = (mask.nelements() == shp(axis)); 98 99 // Columns from Tables 100 101 ROArrayColumn<Float> tSysCol; 102 ROScalarColumn<Double> mjdCol; 103 ROScalarColumn<String> srcNameCol; 104 ROScalarColumn<Double> intCol; 105 ROArrayColumn<uInt> fqIDCol; 106 107 // Create accumulation MaskedArray. We accumulate for each channel,if,pol,beam 108 // Note that the mask of the accumulation array will ALWAYS remain ALL True. 109 // The MA is only used so that when data which is masked Bad is added to it, 110 // that data does not contribute. 111 112 Array<Float> zero(shp); 113 zero=0.0; 114 Array<Bool> good(shp); 115 good = True; 116 MaskedArray<Float> sum(zero,good); 117 118 // Counter arrays 119 120 Array<Float> nPts(shp); // Number of points 121 nPts = 0.0; 122 Array<Float> nInc(shp); // Increment 123 nInc = 1.0; 124 125 // Create accumulation Array for variance. We accumulate for 126 // each if,pol,beam, but average over channel. So we need 127 // a shape with one less axis dropping channels. 128 129 const uInt nAxesSub = shp.nelements() - 1; 130 IPosition shp2(nAxesSub); 131 for (uInt i=0,j=0; i<(nAxesSub+1); i++) { 132 if (i!=axis) { 133 shp2(j) = shp(i); 134 j++; 135 } 136 } 137 Array<Float> sumSq(shp2); 138 sumSq = 0.0; 139 IPosition pos2(nAxesSub,0); // For indexing 140 141 // Time-related accumulators 142 143 Double time; 144 Double timeSum = 0.0; 145 Double intSum = 0.0; 146 Double interval = 0.0; 147 148 // To get the right shape for the Tsys accumulator we need to 149 // access a column from the first table. The shape of this 150 // array must not change 151 152 Array<Float> tSysSum; 153 { 154 const Table& tabIn = in[0]->table(); 155 tSysCol.attach(tabIn,"TSYS"); 156 tSysSum.resize(tSysCol.shape(0)); 157 } 158 tSysSum =0.0; 159 Array<Float> tSys; 160 161 // Scan and row tracking 162 163 Int oldScanID = 0; 164 Int outScanID = 0; 165 Int scanID = 0; 166 Int rowStart = 0; 167 Int nAccum = 0; 168 Int tableStart = 0; 169 170 // Source and FreqID 171 172 String sourceName, oldSourceName, sourceNameStart; 173 Vector<uInt> freqID, freqIDStart, oldFreqID; 174 175 // Loop over tables 176 177 Float fac = 1.0; 178 const uInt nTables = in.nelements(); 179 for (uInt iTab=0; iTab<nTables; iTab++) { 180 181 // Attach columns to Table 182 183 const Table& tabIn = in[iTab]->table(); 184 tSysCol.attach(tabIn, "TSYS"); 185 mjdCol.attach(tabIn, "TIME"); 186 srcNameCol.attach(tabIn, "SRCNAME"); 187 intCol.attach(tabIn, "INTERVAL"); 188 fqIDCol.attach(tabIn, "FREQID"); 189 190 // Loop over rows in Table 191 192 const uInt nRows = in[iTab]->nRow(); 193 for (uInt iRow=0; iRow<nRows; iRow++) { 194 195 // Check conformance 196 197 IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape(); 198 if (!shp.isEqual(shp2)) { 199 throw (AipsError("Shapes for all rows must be the same")); 200 } 201 202 // If we are not doing scan averages, make checks for source and 203 // frequency setup and warn if averaging across them 204 205 // Get copy of Scan Container for this row 206 207 SDContainer sc = in[iTab]->getSDContainer(iRow); 208 scanID = sc.scanid; 209 210 // Get quantities from columns 211 212 srcNameCol.getScalar(iRow, sourceName); 213 mjdCol.get(iRow, time); 214 tSysCol.get(iRow, tSys); 215 intCol.get(iRow, interval); 216 fqIDCol.get(iRow, freqID); 217 218 // Initialize first source and freqID 219 220 if (iRow==0 && iTab==0) { 221 sourceNameStart = sourceName; 222 freqIDStart = freqID; 223 } 224 225 // If we are doing scan averages, see if we are at the end of an 226 // accumulation period (scan). We must check soutce names too, 227 // since we might have two tables with one scan each but different 228 // source names; we shouldn't average different sources together 229 230 if (scanAv && ( (scanID != oldScanID) || 231 (iRow==0 && iTab>0 && sourceName!=oldSourceName))) { 232 233 // Normalize data in 'sum' accumulation array according to weighting scheme 234 235 normalize (sum, sumSq, nPts, wtType, axis, nAxesSub); 236 237 // Fill scan container. The source and freqID come from the 238 // first row of the first table that went into this average ( 239 // should be the same for all rows in the scan average) 240 241 Float nR(nAccum); 242 fillSDC (sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID, 243 timeSum/nR, intSum, sourceNameStart, freqIDStart); 244 245 // Write container out to Table 246 247 pTabOut->putSDContainer(sc); 248 249 // Reset accumulators 250 251 sum = 0.0; 252 sumSq = 0.0; 253 nAccum = 0; 254 // 255 tSysSum =0.0; 256 timeSum = 0.0; 257 intSum = 0.0; 258 259 // Increment 260 261 rowStart = iRow; // First row for next accumulation 262 tableStart = iTab; // First table for next accumulation 263 sourceNameStart = sourceName; // First source name for next accumulation 264 freqIDStart = freqID; // First FreqID for next accumulation 265 // 266 oldScanID = scanID; 267 outScanID += 1; // Scan ID for next accumulation period 268 } 269 270 // Accumulation step. First get data and deconstruct 271 272 MaskedArray<Float> dataIn(in[iTab]->rowAsMaskedArray(iRow)); 273 Array<Float>& valuesIn = dataIn.getRWArray(); // writable reference 274 const Array<Bool>& maskIn = dataIn.getMask(); // RO reference 275 // 276 if (wtType==NONE) { 277 const MaskedArray<Float> n(nInc,dataIn.getMask()); 278 nPts += n; // Only accumulates where mask==T 279 } else if (wtType==VAR) { 280 281 // We are going to average the data, weighted by the noise for each pol, beam and IF. 282 // So therefore we need to iterate through by spectrum (axis 3) 283 284 VectorIterator<Float> itData(valuesIn, axis); 285 ReadOnlyVectorIterator<Bool> itMask(maskIn, axis); 286 while (!itData.pastEnd()) { 287 288 // Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor 289 290 if (useMask) { 291 MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector()); 292 fac = 1.0/variance(tmp); 293 } else { 294 MaskedArray<Float> tmp(itData.vector(),itMask.vector()); 295 fac = 1.0/variance(tmp); 296 } 297 298 // Scale data 299 300 itData.vector() *= fac; // Writes back into 'dataIn' 301 // 302 // Accumulate variance per if/pol/beam averaged over spectrum 303 // This method to get pos2 from itData.pos() is only valid 304 // because the spectral axis is the last one (so we can just 305 // copy the first nAXesSub positions out) 306 307 pos2 = itData.pos().getFirst(nAxesSub); 308 sumSq(pos2) += fac; 309 // 310 itData.next(); 311 itMask.next(); 312 } 313 } else if (wtType==TSYS) { 314 } 315 316 // Accumulate sum of (possibly scaled) data 317 318 sum += dataIn; 319 320 // Accumulate Tsys, time, and interval 321 322 tSysSum += tSys; 323 timeSum += time; 324 intSum += interval; 325 326 // Number of rows in accumulation 327 328 nAccum += 1; 329 oldSourceName = sourceName; 330 oldFreqID = freqID; 331 } 332 } 333 334 // OK at this point we have accumulation data which is either 335 // - accumulated from all tables into one row 336 // or 337 // - accumulated from the last scan average 338 // 339 // Normalize data in 'sum' accumulation array according to weighting scheme 340 341 normalize (sum, sumSq, nPts, wtType, axis, nAxesSub); 342 343 // Create and fill container. The container we clone will be from 344 // the last Table and the first row that went into the current 345 // accumulation. It probably doesn't matter that much really... 346 347 Float nR(nAccum); 348 SDContainer sc = in[tableStart]->getSDContainer(rowStart); 349 fillSDC (sc, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID, 350 timeSum/nR, intSum, sourceNameStart, freqIDStart); 351 // 352 pTabOut->putSDContainer(sc); 353 /* 354 cout << endl; 355 cout << "Last accumulation for output scan ID " << outScanID << endl; 356 cout << " The first row in this accumulation is " << rowStart << endl; 357 cout << " The number of rows accumulated is " << nAccum << endl; 358 cout << " The first table in this accumulation is " << tableStart << endl; 359 cout << " The first source in this accumulation is " << sourceNameStart << endl; 360 cout << " The first freqID in this accumulation is " << freqIDStart << endl; 361 cout << " Average time stamp = " << timeSum/nR << endl; 362 cout << " Integrated time = " << intSum << endl; 363 */ 364 return CountedPtr<SDMemTable>(pTabOut); 365 } 366 367 139 368 140 369 CountedPtr<SDMemTable> … … 304 533 305 534 306 CountedPtr<SDMemTable> SDMath::averages(const Block<CountedPtr<SDMemTable> >& in,307 const Vector<Bool>& mask)308 //309 // Noise weighted averaging of spectra from many Tables. Tables can have different310 // number of rows.311 //312 {313 314 // Setup315 316 const uInt axis = 3; // Spectral axis317 IPosition shp = in[0]->rowAsMaskedArray(0).shape();318 Array<Float> arr(shp);319 Array<Bool> barr(shp);320 Double sumInterval = 0.0;321 const Bool useMask = (mask.nelements() == shp(axis));322 323 // Create data accumulation MaskedArray. We accumulate for each324 // channel,if,pol,beam325 326 Array<Float> zero(shp); zero=0.0;327 Array<Bool> good(shp); good = True;328 MaskedArray<Float> sum(zero,good);329 330 // Create accumulation Array for variance. We accumulate for331 // each if,pol,beam, but average over channel332 333 const uInt nAxesSub = shp.nelements() - 1;334 IPosition shp2(nAxesSub);335 for (uInt i=0,j=0; i<(nAxesSub+1); i++) {336 if (i!=axis) {337 shp2(j) = shp(i);338 j++;339 }340 }341 Array<Float> sumSq(shp2);342 sumSq = 0.0;343 IPosition pos2(nAxesSub,0); // FOr indexing344 //345 Float fac = 1.0;346 const uInt nTables = in.nelements();347 for (uInt iTab=0; iTab<nTables; iTab++) {348 const uInt nRows = in[iTab]->nRow();349 sumInterval += nRows * in[iTab]->getInterval(); // Sum of time intervals350 //351 for (uInt iRow=0; iRow<nRows; iRow++) {352 353 // Check conforms354 355 IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();356 if (!shp.isEqual(shp2)) {357 throw (AipsError("Shapes for all rows must be the same"));358 }359 360 // Get data and deconstruct361 362 MaskedArray<Float> marr(in[iTab]->rowAsMaskedArray(iRow));363 Array<Float>& arr = marr.getRWArray(); // writable reference364 const Array<Bool>& barr = marr.getMask(); // RO reference365 366 // We are going to average the data, weighted by the noise for each367 // pol, beam and IF. So therefore we need to iterate through by368 // spectra (axis 3)369 370 VectorIterator<Float> itData(arr, axis);371 ReadOnlyVectorIterator<Bool> itMask(barr, axis);372 while (!itData.pastEnd()) {373 374 // Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor375 376 if (useMask) {377 MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());378 fac = 1.0/variance(tmp);379 } else {380 MaskedArray<Float> tmp(itData.vector(),itMask.vector());381 fac = 1.0/variance(tmp);382 }383 384 // Scale data385 386 itData.vector() *= fac;387 388 // Accumulate variance per if/pol/beam averaged over spectrum389 // This method to get pos2 from itData.pos() is only valid390 // because the spectral axis is the last one (so we can just391 // copy the first nAXesSub positions out)392 393 pos2 = itData.pos().getFirst(nAxesSub);394 sumSq(pos2) += fac;395 //396 itData.next();397 itMask.next();398 }399 400 // Accumulate sums401 402 sum += marr;403 }404 }405 406 // Normalize by the sum of the 1/var.407 408 Array<Float>& data = sum.getRWArray();409 VectorIterator<Float> itData(data, axis);410 while (!itData.pastEnd()) {411 pos2 = itData.pos().getFirst(nAxesSub); // See comments above412 itData.vector() /= sumSq(pos2);413 itData.next();414 }415 416 // Create and fill output417 418 Array<uChar> outflags(shp);419 convertArray(outflags,!(sum.getMask()));420 //421 SDContainer sc = in[0]->getSDContainer(); // CLone from first container of first Table422 sc.putSpectrum(data);423 sc.putFlags(outflags);424 sc.interval = sumInterval;425 //426 SDMemTable* sdmt = new SDMemTable(*in[0],True); // CLone from first Table427 sdmt->putSDContainer(sc);428 return CountedPtr<SDMemTable>(sdmt);429 }430 431 535 432 536 CountedPtr<SDMemTable> … … 655 759 // Get statistic 656 760 657 result[ii] = SDMath::theStatistic(which, tmp);761 result[ii] = mathutil::statistics(which, tmp); 658 762 } 659 763 // … … 661 765 } 662 766 663 664 float SDMath::theStatistic(const std::string& which, const casa::MaskedArray<Float>& data) 665 { 666 String str(which); 667 str.upcase(); 668 if (str.contains(String("MIN"))) { 669 return min(data); 670 } else if (str.contains(String("MAX"))) { 671 return max(data); 672 } else if (str.contains(String("SUMSQ"))) { 673 return sumsquares(data); 674 } else if (str.contains(String("SUM"))) { 675 return sum(data); 676 } else if (str.contains(String("MEAN"))) { 677 return mean(data); 678 } else if (str.contains(String("VAR"))) { 679 return variance(data); 680 } else if (str.contains(String("STDDEV"))) { 681 return stddev(data); 682 } else if (str.contains(String("AVDEV"))) { 683 return avdev(data); 684 } else if (str.contains(String("RMS"))) { 685 uInt n = data.nelementsValid(); 686 return sqrt(sumsquares(data)/n); 687 } else if (str.contains(String("MED"))) { 688 return median(data); 767 void SDMath::fillSDC (SDContainer& sc, 768 const Array<Bool>& mask, 769 const Array<Float>& data, 770 const Array<Float>& tSys, 771 Int scanID, Double timeStamp, 772 Double interval, const String& sourceName, 773 const Vector<uInt>& freqID) 774 { 775 sc.putSpectrum(data); 776 // 777 Array<uChar> outflags(mask.shape()); 778 convertArray(outflags,!mask); 779 sc.putFlags(outflags); 780 // 781 sc.putTsys(tSys); 782 783 // Time things 784 785 sc.timestamp = timeStamp; 786 sc.interval = interval; 787 sc.scanid = scanID; 788 // 789 sc.sourcename = sourceName; 790 sc.putFreqMap(freqID); 791 } 792 793 void SDMath::normalize (MaskedArray<Float>& sum, 794 const Array<Float>& sumSq, 795 const Array<Float>& nPts, 796 weightType wtType, Int axis, 797 Int nAxesSub) 798 { 799 IPosition pos2(nAxesSub,0); 800 // 801 if (wtType==NONE) { 802 803 // We just average by the number of points accumulated. 804 // We need to make a MA out of nPts so that no divide by 805 // zeros occur 806 807 MaskedArray<Float> t(nPts, (nPts>Float(0.0))); 808 sum /= t; 809 } else if (wtType==VAR) { 810 811 // Normalize each spectrum by sum(1/var) where the variance 812 // is worked out for each spectrum 813 814 Array<Float>& data = sum.getRWArray(); 815 VectorIterator<Float> itData(data, axis); 816 while (!itData.pastEnd()) { 817 pos2 = itData.pos().getFirst(nAxesSub); 818 itData.vector() /= sumSq(pos2); 819 itData.next(); 820 } 821 } else if (wtType==TSYS) { 689 822 } 690 823 } 824 -
trunk/src/SDMath.h
r139 r144 43 43 namespace SDMath { 44 44 //public: 45 casa::CountedPtr<SDMemTable> average(const casa::CountedPtr<SDMemTable>& in);46 45 casa::CountedPtr<SDMemTable> quotient(const casa::CountedPtr<SDMemTable>& on, 47 46 const casa::CountedPtr<SDMemTable>& off); 47 48 48 void multiplyInSitu(SDMemTable* in, casa::Float factor); 49 49 50 50 casa::CountedPtr<SDMemTable> multiply(const casa::CountedPtr<SDMemTable>& in, 51 51 casa::Float factor); 52 52 53 casa::CountedPtr<SDMemTable> add(const casa::CountedPtr<SDMemTable>& in, 53 54 casa::Float offset); … … 55 56 casa::CountedPtr<SDMemTable> hanning(const casa::CountedPtr<SDMemTable>& in); 56 57 57 casa::CountedPtr<SDMemTable> 58 averages(const casa::Block<casa::CountedPtr<SDMemTable> >& in, 59 const casa::Vector<casa::Bool>& mask); 58 casa::CountedPtr<SDMemTable> 59 average (const casa::Block<casa::CountedPtr<SDMemTable> >& in, 60 const casa::Vector<casa::Bool>& mask, 61 bool scanAverage, const std::string& weightStr); 60 62 61 63 casa::CountedPtr<SDMemTable> … … 70 72 // private (not actually...) 71 73 72 float theStatistic(const std::string& which, const casa::MaskedArray<casa::Float>& data); 73 74 enum weightType {NONE,VAR,TSYS}; 75 76 void fillSDC (SDContainer& sc, const casa::Array<casa::Bool>& mask, 77 const casa::Array<casa::Float>& data, 78 const casa::Array<casa::Float>& tSys, 79 casa::Int scanID, casa::Double timeStamp, 80 casa::Double interval, const casa::String& sourceName, 81 const casa::Vector<casa::uInt>& freqID); 82 void normalize (casa::MaskedArray<casa::Float>& data, 83 const casa::Array<casa::Float>& sumSq, 84 const casa::Array<casa::Float>& nPts, 85 weightType wtType, casa::Int axis, casa::Int nAxes); 86 87 74 88 }; 75 89
Note:
See TracChangeset
for help on using the changeset viewer.