LCOV - code coverage report
Current view: top level - singledish/SingleDish - SDMSManager.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 260 0.0 %
Date: 2024-10-10 15:00:01 Functions: 0 17 0.0 %

          Line data    Source code
       1             : //# SDMSManager.cc: this defines single dish MS transform manager
       2             : //#                inheriting MSTransformManager.
       3             : //#
       4             : //# Copyright (C) 2015
       5             : //# National Astronomical Observatory of Japan
       6             : //#
       7             : //# This library is free software; you can redistribute it and/or modify it
       8             : //# under the terms of the GNU Library General Public License as published by
       9             : //# the Free Software Foundation; either version 2 of the License, or (at your
      10             : //# option) any later version.
      11             : //#
      12             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      13             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      15             : //# License for more details.
      16             : //#
      17             : //# You should have received a copy of the GNU Library General Public License
      18             : //# along with this library; if not, write to the Free Software Foundation,
      19             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      20             : //#
      21             : //# Correspondence concerning AIPS++ should be addressed as follows:
      22             : //#        Internet email: casa-feedback@nrao.edu.
      23             : //#        Postal address: AIPS++ Project Office
      24             : //#                        National Radio Astronomy Observatory
      25             : //#                        520 Edgemont Road
      26             : //#                        Charlottesville, VA 22903-2475 USA
      27             : //#
      28             : //# $Id$
      29             : #include <algorithm>
      30             : #include <array>
      31             : #include <iostream>
      32             : #include <iterator>
      33             : #include <list>
      34             : 
      35             : //#include <libsakura/sakura.h>
      36             : //#include <libsakura/config.h>
      37             : 
      38             : #include <casacore/casa/Logging/LogIO.h>
      39             : #include <casacore/casa/Logging/LogOrigin.h>
      40             : #include <casacore/casa/Utilities/Assert.h>
      41             : #include <casacore/casa/Arrays/ArrayMath.h>
      42             : #include <casacore/casa/Utilities/Sort.h>
      43             : 
      44             : #include <casacore/ms/MSSel/MSSelectionTools.h>
      45             : #include <msvis/MSVis/VisibilityIterator2.h>
      46             : #include <msvis/MSVis/VisSetUtil.h>
      47             : 
      48             : #include <casa_sakura/SakuraUtils.h>
      49             : #include <singledish/SingleDish/SDMSManager.h>
      50             : 
      51             : 
      52             : #define _ORIGIN LogOrigin("SDMSManager", __func__, WHERE)
      53             : 
      54             : using namespace casacore;
      55             : 
      56             : namespace casa {
      57             : 
      58           0 : SDMSManager::SDMSManager() : doSmoothing_(false) {
      59           0 : }
      60             : 
      61             : // SDMSManager &SDMSManager::operator=(SDMSManager const &other)
      62             : // {
      63             : //   return *this;
      64             : // }
      65             : 
      66           0 : SDMSManager::~SDMSManager() {
      67           0 :   LogIO os(_ORIGIN);
      68           0 : }
      69             : 
      70             : // -----------------------------------------------------------------------
      71             : // Fill output MS with data from an input VisBuffer
      72             : // -----------------------------------------------------------------------
      73           0 : void SDMSManager::fillCubeToOutputMs(vi::VisBuffer2 *vb,Cube<Float> const &data_cube,
      74             :                                      Cube<Bool> const *flag_cube, Matrix<Float> const *weight_matrix) {
      75           0 :   setupBufferTransformations(vb);
      76             : 
      77             :   // make sure the shape of cube matches the number of rows to add.
      78           0 :   AlwaysAssert(data_cube.nplane() == nRowsToAdd_p, AipsError);
      79             : 
      80           0 :   if (bufferMode_p) {
      81           0 :     return;
      82             :   }
      83             : 
      84             :   // Create RowRef object to fill new rows
      85           0 :   uInt currentRows = outputMs_p->nrow();
      86           0 :   RefRows rowRef(currentRows, currentRows + nRowsToAdd_p / nspws_p - 1);
      87             : 
      88             :   // Add new rows to output MS
      89           0 :   outputMs_p->addRow(nRowsToAdd_p, false);
      90             : 
      91             :   // Fill new rows
      92           0 :   if (weight_matrix == nullptr) {
      93           0 :     weightSpectrumFlatFilled_p = false;
      94           0 :     weightSpectrumFromSigmaFilled_p = false;
      95           0 :     fillWeightCols(vb, rowRef);
      96             :   }
      97           0 :   fillCubeToDataCols(vb, rowRef, data_cube, flag_cube);
      98           0 :   fillIdCols(vb, rowRef);
      99           0 :   if (weight_matrix != nullptr) { // for update_weight=True (CAS-13161)
     100           0 :     outputMsCols_p->weight().putColumnCells(rowRef, *weight_matrix);
     101             :   }
     102           0 : }
     103             : 
     104             : // ----------------------------------------------------------------------------------------
     105             : // Fill main (data) columns which have to be combined together to produce bigger SPWs
     106             : // ----------------------------------------------------------------------------------------
     107           0 : void SDMSManager::fillCubeToDataCols(vi::VisBuffer2 *vb, RefRows &rowRef,
     108             :                                      Cube<Float> const &data_cube, Cube<Bool> const *flag_cube) {
     109           0 :   ArrayColumn<Bool> *outputFlagCol = NULL;
     110           0 :   for (dataColMap::iterator iter = dataColMap_p.begin(); iter != dataColMap_p.end(); iter++) {
     111             :     // Get applicable *_SPECTRUM (copy constructor uses reference semantics)
     112             :     // If channel average or combine, otherwise no need to copy
     113           0 :     const Cube<Float> applicableSpectrum = getApplicableSpectrum(vb, iter->first);
     114             : 
     115             :     // Apply transformations
     116           0 :     switch (iter->first) {
     117           0 :     case MS::DATA:
     118             :       {
     119           0 :         if (mainColumn_p == MS::DATA) {
     120           0 :           outputFlagCol = &(outputMsCols_p->flag());
     121           0 :           setTileShape(rowRef, outputMsCols_p->flag());
     122             :         } else {
     123           0 :           outputFlagCol = NULL;
     124             :         }
     125           0 :         setTileShape(rowRef, outputMsCols_p->data());
     126           0 :         Cube<Complex> cdata_cube(data_cube.shape());
     127           0 :         convertArray(cdata_cube, data_cube);
     128           0 :         transformCubeOfData(vb, rowRef, cdata_cube, outputMsCols_p->data(),
     129             :                             outputFlagCol, applicableSpectrum);
     130           0 :         break;
     131           0 :       }
     132           0 :     case MS::CORRECTED_DATA:
     133             :       {
     134           0 :         if (mainColumn_p == MS::CORRECTED_DATA) {
     135           0 :           outputFlagCol = &(outputMsCols_p->flag());
     136           0 :           setTileShape(rowRef, outputMsCols_p->flag());
     137             :         } else {
     138           0 :           outputFlagCol = NULL;
     139             :         }
     140           0 :         Cube<Complex> cdata_cube(data_cube.shape());
     141           0 :         convertArray(cdata_cube, data_cube);
     142           0 :         if (iter->second == MS::DATA) {
     143           0 :           setTileShape(rowRef, outputMsCols_p->data());
     144           0 :           transformCubeOfData(vb, rowRef, cdata_cube, outputMsCols_p->data(),
     145             :                               outputFlagCol, applicableSpectrum);
     146             :         } else {
     147           0 :           setTileShape(rowRef, outputMsCols_p->correctedData());
     148           0 :           transformCubeOfData(vb, rowRef, cdata_cube, outputMsCols_p->correctedData(),
     149             :                               outputFlagCol, applicableSpectrum);
     150             :         }
     151           0 :         break;
     152           0 :       }
     153           0 :     case MS::MODEL_DATA:
     154             :       {
     155           0 :         if (mainColumn_p == MS::MODEL_DATA) {
     156           0 :           outputFlagCol = &(outputMsCols_p->flag());
     157           0 :           setTileShape(rowRef, outputMsCols_p->flag());
     158             :         } else {
     159           0 :           outputFlagCol = NULL;
     160             :         }
     161             : 
     162           0 :         if (iter->second == MS::DATA) {
     163           0 :           setTileShape(rowRef, outputMsCols_p->data());
     164           0 :           transformCubeOfData(vb, rowRef, vb->visCubeModel(), outputMsCols_p->data(),
     165             :                               outputFlagCol, applicableSpectrum);
     166             :         } else {
     167           0 :           setTileShape(rowRef, outputMsCols_p->modelData());
     168           0 :           transformCubeOfData(vb, rowRef, vb->visCubeModel(), outputMsCols_p->modelData(),
     169             :                               outputFlagCol, applicableSpectrum);
     170             :         }
     171           0 :         break;
     172             :       }
     173           0 :     case MS::FLOAT_DATA:
     174             :       {
     175           0 :         if (mainColumn_p == MS::FLOAT_DATA) {
     176           0 :           outputFlagCol = &(outputMsCols_p->flag());
     177           0 :           setTileShape(rowRef, outputMsCols_p->flag());
     178             :         } else {
     179           0 :           outputFlagCol = NULL;
     180             :         }
     181           0 :         setTileShape(rowRef, outputMsCols_p->floatData());
     182           0 :         transformCubeOfData(vb, rowRef, data_cube, outputMsCols_p->floatData(),
     183             :                             outputFlagCol, applicableSpectrum);
     184           0 :         break;
     185             :       }
     186           0 :     case MS::LAG_DATA:
     187             :       {
     188             :         // jagonzal: TODO
     189           0 :         break;
     190             :       }
     191           0 :     default:
     192             :       {
     193             :         // jagonzal: TODO
     194           0 :         break;
     195             :       }
     196             :     } // end switch
     197             : 
     198             :     //KS: THIS PART ASSUMES INROW==OUTROW
     199           0 :     if ((outputFlagCol != NULL) && (flag_cube != nullptr)) {
     200           0 :       setTileShape(rowRef, outputMsCols_p->flag());
     201           0 :       writeCube(*flag_cube, *outputFlagCol, rowRef);
     202             :     }
     203           0 :   } // end loop for dataColMap
     204             : 
     205             :   // Special case for flag category
     206           0 :   if (inputFlagCategoryAvailable_p) {
     207           0 :     if (spectrumReshape_p) {
     208           0 :       IPosition transformedCubeShape = getShape(); //[nC,nF,nR]
     209           0 :       IPosition inputFlagCategoryShape = vb->flagCategory().shape(); // [nC,nF,nCategories,nR]
     210             :       IPosition flagCategoryShape(4,
     211           0 :                                   inputFlagCategoryShape(1),
     212           0 :                                   transformedCubeShape(2),
     213           0 :                                   inputFlagCategoryShape(2),
     214           0 :                                   transformedCubeShape(2));
     215           0 :       Array<Bool> flagCategory(flagCategoryShape, false);
     216             : 
     217           0 :       outputMsCols_p->flagCategory().putColumnCells(rowRef, flagCategory);
     218           0 :     } else {
     219           0 :       outputMsCols_p->flagCategory().putColumnCells(rowRef, vb->flagCategory());
     220             :     }
     221             :   }
     222             : 
     223           0 :   return;
     224             : }
     225             : 
     226             : // -----------------------------------------------------------------------
     227             : // Method to determine sort columns order
     228             : // -----------------------------------------------------------------------
     229           0 : void SDMSManager::setSortColumns(Block<Int> sortColumns,
     230             :                                  bool addDefaultSortCols,
     231             :                                  Double timebin) {
     232           0 :   size_t const num_in = sortColumns.nelements();
     233           0 :   LogIO os(_ORIGIN);
     234           0 :   os << "Setting user sort columns with " << num_in << " elements" << LogIO::POST;
     235           0 :   if (addDefaultSortCols) {
     236           0 :     Block<Int> defaultCols(6);
     237           0 :     defaultCols[0] = MS::OBSERVATION_ID;
     238           0 :     defaultCols[1] = MS::ARRAY_ID;
     239             :     // Assuming auto-correlation here
     240           0 :     defaultCols[2] = MS::ANTENNA1;
     241           0 :     defaultCols[3] = MS::FEED1;
     242           0 :     defaultCols[4] = MS::DATA_DESC_ID;
     243           0 :     defaultCols[5] = MS::TIME;
     244           0 :     os << "Adding default sort columns to user sort column" << LogIO::POST;
     245           0 :     if (num_in > 0) {
     246           0 :       size_t num_elem(num_in);
     247           0 :       sortColumns.resize(num_in + defaultCols.nelements(), false, true);
     248           0 :       for (size_t i = 0; i < defaultCols.nelements(); ++i) {
     249           0 :         bool addcol = true;
     250           0 :         if (getBlockId(sortColumns, defaultCols[i]) > -1) {
     251           0 :           addcol = false; // the columns is in sortColumns
     252             :         }
     253           0 :         if (addcol) {
     254           0 :           sortColumns[num_elem] = defaultCols[i];
     255           0 :           ++num_elem;
     256             :         }
     257             :       }
     258             :       // shrink block
     259           0 :       sortColumns.resize(num_elem, true, true);
     260           0 :       userSortCols_ = sortColumns;
     261             :     } else {
     262           0 :       userSortCols_ = defaultCols;
     263             :     }
     264           0 :   } else { // do not add
     265           0 :     if (num_in > 0) {
     266           0 :       userSortCols_ = sortColumns;
     267             :     } else {
     268           0 :       userSortCols_ = Block<Int>();
     269             :     }
     270             :   }
     271           0 :   os << "Defined user sort columns with " << userSortCols_.nelements() << " elements" << LogIO::POST;
     272           0 :   timeBin_p = timebin;
     273           0 :   os << "Time bin is " << timeBin_p << " sec" << LogIO::POST;
     274             :   // regenerate iterator if necessary
     275           0 :   if (visibilityIterator_p != NULL) {
     276           0 :     os << "Regenerating iterator" << LogIO::POST;
     277           0 :     setIterationApproach();
     278           0 :     generateIterator();
     279             :   }
     280             : 
     281           0 :   return;
     282           0 : }
     283             : 
     284           0 : int SDMSManager::getBlockId(Block<Int> const &data, Int const value) {
     285           0 :   for (size_t i = 0; i < data.nelements(); ++i) {
     286           0 :     if (data[i] == value) {
     287           0 :       return (int)i;
     288             :     }
     289             :   }
     290             : 
     291           0 :   return -1;
     292             : }
     293             : 
     294           0 : void SDMSManager::setIterationApproach() {
     295           0 :   if (userSortCols_.nelements() == 0) {
     296           0 :     sortColumns_p = Block<Int>();
     297             : 
     298           0 :     return;
     299             :   }
     300             : 
     301             :   // User column is set.
     302           0 :   logger_p.origin(_ORIGIN);
     303             : 
     304             :   using ColumnId = MSMainEnums::PredefinedColumns;
     305             :   struct CheckItem {
     306           0 :     CheckItem(ColumnId const &id, String const &name, String const &type, Bool const &remove)
     307           0 :         : columnId{id}, columnName{name}, paramType{type}, removeIt{remove}, addIt{!remove}
     308           0 :     {}
     309             :     ColumnId columnId;
     310             :     String columnName;
     311             :     String paramType;
     312             :     Bool removeIt;
     313             :     Bool addIt;
     314             :   };
     315           0 :   auto const userSortColExists = [&](ColumnId const &columnId) {
     316           0 :     return getBlockId(userSortCols_, columnId) > -1;
     317           0 :   };
     318             : 
     319             :   // copy userSortCols_ to std::list
     320           0 :   std::list<ColumnId> userSortColsList;
     321           0 :   std::transform(
     322             :     userSortCols_.begin(), userSortCols_.end(),
     323             :     std::back_inserter(userSortColsList),
     324           0 :     [](Int const &i) {return static_cast<ColumnId>(i);}
     325             :   );
     326             : 
     327             :   // list of columns that may be added/removed depending on the value of timespan_p
     328             :   std::array<CheckItem, 3> const checkList {{
     329           0 :     {MS::SCAN_NUMBER, "SCAN_NUMBER", "scan", timespan_p.contains("scan")},
     330           0 :     {MS::STATE_ID, "STATE_ID", "state", timespan_p.contains("state")},
     331           0 :     {MS::FIELD_ID, "FIELD_ID", "field", timespan_p.contains("field")},
     332           0 :   }};
     333             : 
     334             :   // remove columns from userSortColsList if necessary
     335           0 :   for (auto const &item: checkList) {
     336           0 :     if (item.removeIt && userSortColExists(item.columnId)) {
     337           0 :       logger_p << LogIO::NORMAL;
     338           0 :       logger_p << "Combining data through " << item.paramType << "s for time average. ";
     339           0 :       logger_p << "Removing " << item.columnName << " from user sort list." << LogIO::POST;
     340           0 :       userSortColsList.remove(item.columnId);
     341             :     }
     342             :   }
     343             : 
     344             :   // add columns to userSortColsList if necessary
     345           0 :   if (timeAverage_p) {
     346           0 :     for (auto const &item: checkList) {
     347           0 :       if (item.addIt && !userSortColExists(item.columnId)) {
     348           0 :         logger_p << LogIO::NORMAL
     349           0 :                  << "Splitting data by " << item.paramType << "s for time average. "
     350           0 :                  << "Adding " << item.columnName << " to user sort list." << LogIO::POST;
     351           0 :         userSortColsList.push_back(item.columnId);
     352             :       }
     353             :     }
     354             :   }
     355             : 
     356             :   // copy back userSortColsList to sortColumns_p
     357           0 :   constexpr bool forceSmaller = true;
     358           0 :   constexpr bool copyElements = false;
     359           0 :   sortColumns_p.resize(userSortColsList.size(), forceSmaller, copyElements);
     360           0 :   std::transform(
     361             :     userSortColsList.begin(), userSortColsList.end(), sortColumns_p.begin(),
     362           0 :     [](ColumnId const &i) {return static_cast<Int>(i);}
     363             :   );
     364             : 
     365           0 :   ostringstream oss;
     366           0 :   for (size_t i = 0; i < sortColumns_p.nelements(); ++i) {
     367           0 :     oss << sortColumns_p[i] << ", ";
     368             :   }
     369           0 :   logger_p << LogIO::DEBUG1 << "Final Sort order: "
     370           0 :            << oss.str() << LogIO::POST;
     371             : 
     372           0 :   return;
     373           0 : }
     374             : 
     375           0 : Record SDMSManager::getSelRec(string const &spw) {
     376           0 :   MeasurementSet myms = MeasurementSet(inpMsName_p);
     377           0 :   return myms.msseltoindex(toCasaString(spw));
     378           0 : }
     379             : 
     380             : /*
     381             : MeasurementSet SDMSManager::getMS()
     382             : {
     383             :   MeasurementSet myms = MeasurementSet(inpMsName_p);
     384             :   return myms;
     385             : }
     386             : */
     387             : 
     388           0 : void SDMSManager::setSmoothing(string const &kernelType, float const &kernelWidth) {
     389             :   // kernel type
     390           0 :   VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernelType);
     391             : 
     392             :   // Fail if type is neither GAUSSIAN nor BOXCAR since other ones are yet to be supported
     393           0 :   if ((type != VectorKernel::GAUSSIAN) && (type != VectorKernel::BOXCAR)) {
     394           0 :     stringstream oss;
     395           0 :     oss << "Smoothing kernel type \"" << kernelType << "\" is not supported yet.";
     396           0 :     throw AipsError(oss.str());
     397           0 :   }
     398             : 
     399             :   // Fail if kernel width is zero or negative
     400           0 :   if (kernelWidth <= 0.0) {
     401           0 :     throw AipsError("Zero or negative kernel width is not allowed.");
     402             :   }
     403             : 
     404           0 :   doSmoothing_ = true;
     405           0 :   kernelType_ = type;
     406           0 :   kernelWidth_ = kernelWidth;
     407           0 : }
     408             : 
     409           0 : void SDMSManager::unsetSmoothing() {
     410           0 :   doSmoothing_ = false;
     411           0 : }
     412             : 
     413           0 : void SDMSManager::initializeSmoothing() {
     414           0 :   LogIO os(_ORIGIN);
     415           0 :   if (!doSmoothing_) {
     416           0 :     return;
     417             :   }
     418             : 
     419           0 :   Vector<Int> numChanList = inspectNumChan();
     420           0 :   for (size_t i = 0; i < numChanList.nelements(); ++i) {
     421           0 :     Int numChan = numChanList[i];
     422           0 :     Vector<Float> theKernel = VectorKernel::make(kernelType_, kernelWidth_, numChan, true, false);
     423             :     //shift 1 channel for boxcar kernel---(for CAS-7442, 2015/11/18 WK)
     424           0 :     if (kernelType_ == VectorKernel::BOXCAR) {
     425           0 :       for (size_t j = theKernel.nelements()-1; j >= 1; --j) {
     426           0 :         theKernel[j] = theKernel[j-1];
     427             :       }
     428           0 :       theKernel[0] = 0.0;
     429             :     }
     430             :     //------
     431           0 :     convolverPool_[numChan] = Convolver<Float>();
     432           0 :     convolverPool_[numChan].setPsf(theKernel, IPosition(1, numChan));
     433           0 :   }
     434             : 
     435             :   // set smoothing kernel for weight
     436           0 :   smoothBin_p = static_cast<uInt>(kernelWidth_ + 0.5f);
     437           0 :   smoothBin_p += (smoothBin_p % 2 == 0) ? 1 : 0; // to make smoothBin_p odd
     438           0 :   uInt numChanMinimum = min(numChanList);
     439           0 :   smoothBin_p = min(smoothBin_p, numChanMinimum - ((numChanMinimum % 2 == 0) ? 1 : 0)); // smoothBin_p < numChanMinimum
     440           0 :   uInt halfWidth = smoothBin_p / 2;
     441           0 :   Sort sort;
     442           0 :   Vector<Float> kernelForMinimumNumChan = convolverPool_[numChanMinimum].getPsf();
     443           0 :   sort.sortKey(kernelForMinimumNumChan.data(), TpFloat, 0, Sort::Descending);
     444           0 :   Vector<uInt> indexArray;
     445             :   //uInt indexArrayLength = sort.sort(indexArray, numChanMinimum);
     446           0 :   sort.sort(indexArray, numChanMinimum);
     447           0 :   uInt startChan = indexArray[0] - halfWidth;
     448           0 :   uInt endChan = startChan + smoothBin_p;
     449           0 :   smoothCoeff_p.resize(smoothBin_p, false);
     450           0 :   for (uInt i = startChan, j = 0; i < endChan; ++i, ++j) {
     451           0 :     smoothCoeff_p[j] = kernelForMinimumNumChan[i];
     452             :   }
     453             :   // normalize smoothCoeff_p
     454           0 :   smoothCoeff_p /= sum(smoothCoeff_p);
     455           0 :   os << LogIO::DEBUGGING << "smoothBin_p = " << smoothBin_p << LogIO::POST;
     456           0 :   os << LogIO::DEBUGGING << "smoothCoeff_p = " << smoothCoeff_p << LogIO::POST;
     457           0 : }
     458             : 
     459           0 : Vector<Int> SDMSManager::inspectNumChan() {
     460           0 :   LogIO os(_ORIGIN);
     461             : 
     462           0 :   if (selectedInputMs_p == NULL) {
     463           0 :     throw AipsError("Input MS is not opened yet.");
     464             :   }
     465             : 
     466           0 :   ScalarColumn<Int> col(*selectedInputMs_p, "DATA_DESC_ID");
     467           0 :   Vector<Int> ddIdList = col.getColumn();
     468           0 :   uInt numDDId = GenSort<Int>::sort(ddIdList, Sort::Ascending,
     469             :                                     Sort::QuickSort | Sort::NoDuplicates);
     470           0 :   col.attach(selectedInputMs_p->dataDescription(), "SPECTRAL_WINDOW_ID");
     471           0 :   Vector<Int> spwIdList(numDDId);
     472           0 :   for (uInt i = 0; i < numDDId; ++i) {
     473           0 :     spwIdList[i] = col(ddIdList[i]);
     474             :   }
     475           0 :   Vector<Int> numChanList(numDDId);
     476           0 :   col.attach(selectedInputMs_p->spectralWindow(), "NUM_CHAN");
     477           0 :   os << LogIO::DEBUGGING << "spwIdList = " << spwIdList << LogIO::POST;
     478           0 :   for (size_t i = 0; i < spwIdList.nelements(); ++i) {
     479           0 :     Int spwId = spwIdList[i];
     480           0 :     Int numChan = col(spwId);
     481           0 :     numChanList[i] = numChan;
     482           0 :     os << LogIO::DEBUGGING << "examine spw " << spwId << ": nchan = " << numChan << LogIO::POST;
     483           0 :     if (numChan == 1) {
     484           0 :       stringstream ss;
     485           0 :       ss << "smooth: Failed due to wrong spw " << i;
     486           0 :       throw AipsError(ss.str());
     487           0 :     }
     488             :   }
     489             : 
     490           0 :   uInt numNumChan = GenSort<Int>::sort(numChanList, Sort::Ascending,
     491             :                                        Sort::QuickSort | Sort::NoDuplicates);
     492           0 :   return numChanList(Slice(0, numNumChan));
     493           0 : }
     494             : 
     495             : }  // End of casa namespace.

Generated by: LCOV version 1.16