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