LCOV - code coverage report
Current view: top level - imageanalysis/ImageAnalysis - ImageCollapser.tcc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 331 0.0 %
Date: 2024-12-11 20:54:31 Functions: 0 14 0.0 %

          Line data    Source code
       1             : //# Copyright (C) 1998,1999,2000,2001,2003
       2             : //# Associated Universities, Inc. Washington DC, USA.
       3             : //#
       4             : //# This program is free software; you can redistribute it and/or modify it
       5             : //# under the terms of the GNU General Public License as published by the Free
       6             : //# Software Foundation; either version 2 of the License, or (at your option)
       7             : //# any later version.
       8             : //#
       9             : //# This program is distributed in the hope that it will be useful, but WITHOUT
      10             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      11             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      12             : //# more details.
      13             : //#
      14             : //# You should have received a copy of the GNU General Public License along
      15             : //# with this program; if not, write to the Free Software Foundation, Inc.,
      16             : //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      17             : //#
      18             : //# Correspondence concerning AIPS++ should be addressed as follows:
      19             : //#        Internet email: casa-feedback@nrao.edu.
      20             : //#        Postal address: AIPS++ Project Office
      21             : //#                        National Radio Astronomy Observatory
      22             : //#                        520 Edgemont Road
      23             : //#                        Charlottesville, VA 22903-2475 USA
      24             : //#
      25             : 
      26             : #include <imageanalysis/ImageAnalysis/ImageCollapser.h>
      27             : 
      28             : #include <casacore/casa/Arrays/ArrayLogical.h>
      29             : #include <casacore/casa/BasicSL/STLIO.h>
      30             : #include <casacore/scimath/StatsFramework/ClassicalStatistics.h>
      31             : #include <casacore/scimath/Mathematics/NumericTraits.h>
      32             : #include <casacore/images/Images/ImageStatistics.h>
      33             : #include <casacore/images/Images/ImageUtilities.h>
      34             : #include <casacore/images/Images/PagedImage.h>
      35             : #include <imageanalysis/ImageAnalysis/SubImageFactory.h>
      36             : #include <casacore/images/Images/TempImage.h>
      37             : #include <casacore/lattices/Lattices/LatticeUtilities.h>
      38             : #include <casacore/lattices/LatticeMath/LatticeMathUtil.h>
      39             : 
      40             : #include <imageanalysis/ImageAnalysis/ImageMaskedPixelReplacer.h>
      41             : 
      42             : #include <memory>
      43             : 
      44             : namespace casa {
      45             : 
      46           0 : template<class T> ImageCollapser<T>::ImageCollapser(
      47             :     const casacore::String & aggString, const SPCIIT image,
      48             :     const casacore::Record * const regionRec,
      49             :     const casacore::String & maskInp, const casacore::IPosition & axes,
      50             :     casacore::Bool invertAxesSelection,
      51             :     const casacore::String & outname, casacore::Bool overwrite
      52             : ) : ImageTask<T>(
      53             :         image, "", regionRec, "", "", "",
      54             :         maskInp, outname, overwrite
      55           0 :     ), _invertAxesSelection(invertAxesSelection),
      56           0 :     _axes(axes), _aggType(ImageCollapserData::UNKNOWN) {
      57           0 :     _aggType = ImageCollapserData::aggregateType(aggString);
      58           0 :     this->_construct();
      59           0 :     _finishConstruction();
      60           0 : }
      61             : 
      62           0 : template<class T> ImageCollapser<T>::ImageCollapser(
      63             :     const SPCIIT image,
      64             :     const casacore::IPosition & axes, const casacore::Bool invertAxesSelection,
      65             :     const ImageCollapserData::AggregateType aggregateType,
      66             :     const casacore::String & outname, const casacore::Bool overwrite
      67             : ) : ImageTask<T>(image, "", 0, "", "", "", "", outname, overwrite),
      68           0 :     _invertAxesSelection(invertAxesSelection),
      69           0 :     _axes(axes), _aggType(aggregateType) {
      70           0 :     ThrowIf (
      71             :         _aggType == ImageCollapserData::UNKNOWN,
      72             :         "UNKNOWN aggregateType not allowed"
      73             :     );
      74           0 :     ThrowIf(
      75             :         ! image,
      76             :         "Cannot use a null image pointer with this constructor"
      77             :     );
      78           0 :     this->_construct();
      79           0 :     _finishConstruction();
      80           0 : }
      81             : 
      82           0 : template<class T> SPIIT ImageCollapser<T>::collapse() const {
      83           0 :     auto subImage = SubImageFactory<T>::createSubImageRO(
      84           0 :         *this->_getImage(), *this->_getRegion(), this->_getMask(),
      85           0 :         this->_getLog().get(), AxesSpecifier(), this->_getStretch()
      86             :     );
      87           0 :     *this->_getLog() << LogOrigin(getClass(), __func__);
      88           0 :     ThrowIf(
      89             :         ImageMask::isAllMaskFalse(*subImage),
      90             :         "All selected pixels are masked"
      91             :     );
      92           0 :     auto outCoords = subImage->coordinates();
      93           0 :     auto hasDir = outCoords.hasDirectionCoordinate();
      94           0 :     auto inShape = subImage->shape();
      95           0 :     if (_aggType == ImageCollapserData::FLUX) {
      96           0 :         _checkFlux(subImage);
      97             :     }
      98             :     // Set the compressed axis reference pixel and reference value
      99           0 :     Vector<Double> blc, trc;
     100           0 :     IPosition pixblc(inShape.nelements(), 0);
     101           0 :     auto pixtrc = inShape - 1;
     102           0 :     ThrowIf(
     103             :         ! outCoords.toWorld(blc, pixblc)
     104             :         || ! outCoords.toWorld(trc, pixtrc),
     105             :         "Could not set new coordinate values"
     106             :     );
     107           0 :     auto refValues = outCoords.referenceValue();
     108           0 :     auto refPixels = outCoords.referencePixel();
     109           0 :     auto outShape = inShape;
     110           0 :     auto degenTypes = ImageCollapserData::aggTypesSupportedDegenAxes();
     111           0 :     auto useDegenCase = degenTypes->find(_aggType) != degenTypes->end();
     112           0 :     for (const auto& axis: _axes) {
     113           0 :         refValues[axis] = (blc[axis] + trc[axis])/2;
     114           0 :         refPixels[axis] = 0;
     115           0 :         outShape[axis] = 1;
     116           0 :         useDegenCase = useDegenCase && inShape[axis] == 1;
     117             :     }
     118           0 :     ThrowIf(
     119             :         ! outCoords.setReferenceValue(refValues),
     120             :         "Unable to set reference value"
     121             :     );
     122           0 :     ThrowIf(
     123             :         ! outCoords.setReferencePixel(refPixels),
     124             :         "Unable to set reference pixel"
     125             :     );
     126           0 :     TempImage<T> tmpIm(outShape, outCoords);
     127           0 :     if (_aggType == ImageCollapserData::ZERO) {
     128           0 :         tmpIm.set(0.0);
     129             :     }
     130           0 :     else if (useDegenCase) {
     131           0 :         _doDegenerateAxesCase(tmpIm, subImage);
     132             :     }
     133           0 :     else if (
     134           0 :         _aggType == ImageCollapserData::MEDIAN
     135           0 :         || _aggType == ImageCollapserData::MADM
     136           0 :         || _aggType == ImageCollapserData::XMADM       
     137             :     ) {
     138           0 :         _doHighPerf(subImage, tmpIm);
     139             :     }
     140             :     else {
     141           0 :         _doOtherStats(tmpIm, subImage);
     142             :     }
     143           0 :     auto copied = subImage->imageInfo().hasMultipleBeams()
     144           0 :         ? _doMultipleBeams(tmpIm, subImage, hasDir, outCoords)
     145             :         : false;
     146           0 :     if (! copied) {
     147           0 :         ImageUtilities::copyMiscellaneous(tmpIm, *subImage, true);
     148             :     }
     149           0 :     if (_aggType == ImageCollapserData::FLUX) {
     150           0 :         _doFluxUnits(tmpIm, subImage);
     151             :     }
     152           0 :     return this->_prepareOutputImage(tmpIm);
     153           0 : }
     154             : 
     155           0 : template<class T> void ImageCollapser<T>::_checkFlux(
     156             :     SPCIIT subImage
     157             : ) const {
     158           0 :     String cant = " Cannot do flux density calculation";
     159           0 :     const auto& outCoords = subImage->coordinates();
     160           0 :     ThrowIf(
     161             :         ! outCoords.hasDirectionCoordinate(),
     162             :         "Image has no direction coordinate." + cant
     163             :     );
     164           0 :     ThrowIf(
     165             :         subImage->units().getName().contains("beam")
     166             :         && ! subImage->imageInfo().hasBeam(),
     167             :         "Image has no beam." + cant
     168             :     );
     169           0 :     auto dirAxes = outCoords.directionAxesNumbers();
     170           0 :     const auto naxes = _axes.size();
     171           0 :     for (uInt i = 0; i < naxes; ++i) {
     172           0 :         Int axis = _axes[i];
     173           0 :         ThrowIf(
     174             :             ! anyTrue(dirAxes == axis)
     175             :             && subImage->shape()[axis] > 1,
     176             :             "Specified axis " + String::toString(axis)
     177             :             + " is not a direction axis but has length > 1." + cant
     178             :         );
     179             :     }
     180           0 : }
     181             : 
     182           0 : template<class T> void ImageCollapser<T>::_doDegenerateAxesCase(
     183             :     TempImage<T>& tmpIm, SPCIIT subImage
     184             : ) const {
     185           0 :     *this->_getLog() << LogOrigin(getClass(), __func__);
     186           0 :     *this->_getLog() << LogIO::NORMAL << "All subimage axes to be "
     187             :         << "collapsed are degenerate, using algorithm optimized for "
     188           0 :         << "that case." << LogIO::POST;
     189           0 :     ThrowIf(
     190             :         _aggType == ImageCollapserData::STDDEV
     191             :         || _aggType == ImageCollapserData::VARIANCE,
     192             :         "Cannot compute "
     193             :         + ImageCollapserData::funcNameMap()->find(_aggType)->second
     194             :         + " for single sample data sets"
     195             :     );
     196           0 :     if (
     197           0 :         _aggType == ImageCollapserData::MAX
     198           0 :         || _aggType == ImageCollapserData::MEAN
     199           0 :         || _aggType == ImageCollapserData::MEDIAN
     200           0 :         || _aggType == ImageCollapserData::MIN
     201           0 :         || _aggType == ImageCollapserData::SUM
     202             :     ) {
     203             :         // Straight copy
     204           0 :         this->_copyData(tmpIm, *subImage);
     205             :     }
     206           0 :     else if (_aggType == ImageCollapserData::NPTS) {
     207           0 :         tmpIm.set(1.0);
     208             :     }
     209           0 :     else if (
     210           0 :         _aggType == ImageCollapserData::MADM
     211           0 :         || _aggType == ImageCollapserData::XMADM
     212             :     ) {
     213           0 :         tmpIm.set(0.0);
     214             :     }
     215           0 :     else if (_aggType == ImageCollapserData::RMS) {
     216           0 :         this->_copyData(tmpIm, LatticeExpr<T>(abs(*subImage)));
     217             :     }
     218             :     else {
     219           0 :         ThrowCc(
     220             :             "Logic error: "
     221             :             + ImageCollapserData::funcNameMap()->find(_aggType)->second
     222             :             + " erroneously not supported for degenerate axis case. Please "
     223             :             + "file a bug report and include this message"
     224             :         );
     225             :     }
     226           0 :     if (subImage->isMasked() && ! ImageMask::isAllMaskTrue(*subImage)) {
     227           0 :         if (! tmpIm.isMasked()) {
     228           0 :             TempLattice<Bool> mask(tmpIm.shape());
     229           0 :             this->_copyMask(mask, *subImage);
     230           0 :             tmpIm.attachMask(mask);
     231           0 :         }
     232             :         // This works because the underlying pixel data are cloned by reference
     233           0 :         SPIIT myclone(tmpIm.cloneII());
     234           0 :         ImageMaskedPixelReplacer<T> impr(myclone);
     235           0 :         impr.replace("0", False, False);
     236           0 :     }
     237           0 : }
     238             : 
     239           0 : template<class T> void ImageCollapser<T>::_doFluxUnits(
     240             :     TempImage<T>& tmpIm, const std::shared_ptr<const SubImage<T>> subImage
     241             : ) const {
     242             :     // get the flux units right
     243           0 :      auto sbunit = subImage->units().getName();
     244           0 :      String unit;
     245           0 :      if (sbunit.contains("K")) {
     246           0 :          casacore::String areaUnit = "arcsec2";
     247           0 :          unit = sbunit + "." + areaUnit;
     248           0 :      }
     249             :      else {
     250           0 :          unit = "Jy";
     251           0 :          if (sbunit.contains("/beam")) {
     252           0 :              uInt iBeam = sbunit.find("/beam");
     253           0 :              unit = sbunit.substr(0, iBeam) + sbunit.substr(iBeam + 5);
     254             :          }
     255             :      }
     256           0 :      tmpIm.setUnits(unit);
     257           0 : }
     258             : 
     259           0 : template<class T> void ImageCollapser<T>::_doHighPerf(
     260             :     SPCIIT image, casacore::TempImage<T>& outImage
     261             : ) const {
     262           0 :     auto doMedian = _aggType == ImageCollapserData::MEDIAN;
     263           0 :     auto doMADM = _aggType == ImageCollapserData::MADM
     264           0 :         || _aggType == ImageCollapserData::XMADM;
     265           0 :     ThrowIf(
     266             :         ! doMedian && ! doMADM,
     267             :         "Logic error, unsupported aggregate type "
     268             :         + String(ImageCollapserData::funcNameMap()->at((uInt)_aggType)) + " for method "
     269             :         + String(__func__)
     270             :     );
     271           0 :     IPosition cursorShape(image->ndim(), 1);
     272           0 :     for (uInt i = 0; i < cursorShape.size(); ++i) {
     273           0 :         for (uInt j = 0; j < _axes.size(); ++j) {
     274           0 :             if (_axes[j] == i) {
     275           0 :                 cursorShape[i] = image->shape()[i];
     276           0 :                 break;
     277             :             }
     278             :         }
     279             :     }
     280           0 :     LatticeStepper stepper(image->shape(), cursorShape);
     281           0 :     std::unique_ptr<Array<Bool>> outMask;
     282             :     // accumtype being the same precision as the input data type is ok here,
     283             :     // since we are only computing the median/madm and not actually accumulating
     284             :     ClassicalStatistics<
     285             :         T, typename Array<T>::const_iterator, Array<Bool>::const_iterator
     286           0 :     > stats;
     287           0 :     auto hasMaskedPixels = ! ImageMask::isAllMaskTrue(*image);
     288           0 :     for (stepper.reset(); !stepper.atEnd(); stepper++) {
     289           0 :         Slicer slicer(
     290             :             stepper.position(), stepper.endPosition(), casacore::Slicer::endIsLast
     291             :         );
     292           0 :         auto data = image->getSlice(slicer);
     293           0 :         Bool isMasked = False;
     294           0 :         Array<Bool> maskSlice;
     295           0 :         if (hasMaskedPixels) {
     296           0 :             maskSlice = image->getMaskSlice(slicer);
     297           0 :             isMasked = ! allTrue(maskSlice);
     298             :         }
     299           0 :         if (isMasked) {
     300           0 :             if (! anyTrue(maskSlice)) {
     301           0 :                 if (! outMask) {
     302           0 :                     outMask.reset(new Array<Bool>(outImage.shape(), true));
     303             :                 }
     304           0 :                 (*outMask)(stepper.position()) = false;
     305           0 :                 outImage.putAt(0, stepper.position());
     306             :             }
     307           0 :             else if (! allTrue(maskSlice)) {
     308           0 :                 stats.setData(data.begin(), maskSlice.begin(), data.size());
     309           0 :                 if (doMedian) {
     310           0 :                     outImage.putAt(stats.getMedian(), stepper.position());
     311             :                 }
     312           0 :                 else if (doMADM) {
     313           0 :                     auto x = stats.getMedianAbsDevMed();
     314           0 :                     if (_aggType == ImageCollapserData::XMADM) {
     315           0 :                         x *= C::probit_3_4;
     316             :                     }
     317           0 :                     outImage.putAt(x, stepper.position());
     318             :                 }
     319             :             }
     320             :         }
     321             :         else {
     322           0 :             stats.setData(data.begin(), data.size());
     323           0 :             if (doMedian) {
     324           0 :                 outImage.putAt(stats.getMedian(), stepper.position());
     325             :             }
     326           0 :             else if (doMADM) {
     327           0 :                 auto x = stats.getMedianAbsDevMed();
     328           0 :                 if (_aggType == ImageCollapserData::XMADM) {
     329           0 :                     x *= C::probit_3_4;
     330             :                 }
     331           0 :                 outImage.putAt(x, stepper.position());
     332             :             }
     333             :         }
     334             :     }
     335           0 :     if (outMask) {
     336           0 :         outImage.attachMask(ArrayLattice<Bool>(*outMask));
     337             :     }
     338           0 : }
     339             : 
     340           0 : template<class T> Bool ImageCollapser<T>::_doMultipleBeams(
     341             :     TempImage<T>& tmpIm, SPCIIT subImage, Bool hasDir,
     342             :     const CoordinateSystem & outCoords
     343             : ) const {
     344           0 :     auto naxes = _axes.size();
     345           0 :     auto dirAxesOnlyCollapse = hasDir && naxes == 2;
     346           0 :     if (dirAxesOnlyCollapse) {
     347           0 :         auto dirAxes = outCoords.directionAxesNumbers();
     348           0 :         dirAxesOnlyCollapse = (_axes[0] == dirAxes[0] && _axes[1] == dirAxes[1])
     349           0 :                               || (_axes[1] == dirAxes[0] && _axes[0] == dirAxes[1]);
     350           0 :     }
     351           0 :     if (! dirAxesOnlyCollapse) {
     352             :         // check for degeneracy of spectral or polarization axes
     353           0 :         auto specAxis = outCoords.spectralAxisNumber(false);
     354           0 :         auto polAxis = outCoords.polarizationAxisNumber(false);
     355           0 :         dirAxesOnlyCollapse = true;
     356           0 :         auto shape = subImage->shape();
     357           0 :         for (uInt i = 0; i < naxes; ++i) {
     358           0 :             auto axis = _axes[i];
     359           0 :             if (
     360           0 :                 (axis == specAxis || axis == polAxis)
     361           0 :                 && shape[axis] > 1
     362             :             ) {
     363           0 :                 dirAxesOnlyCollapse = false;
     364           0 :                 break;
     365             :             }
     366             :         }
     367           0 :     }
     368           0 :     if (! dirAxesOnlyCollapse) {
     369           0 :         LogOrigin lor(getClass(), __func__);
     370           0 :         String msg = "Input image has per plane beams "
     371             :             "but the collapse is not done exclusively along the direction axes. "
     372             :             "The output image will arbitrarily have a single beam which "
     373             :             "is the first beam available in the subimage."
     374             :             "Thus, the image planes will not be convolved to a common "
     375             :             "restoring beam before collapsing. If, however, this is desired, "
     376             :             "then run the task imsmooth or the tool method ia.convolve2d() first, "
     377             :             "and use the output image of that as the input for collapsing.";
     378           0 :         *this->_getLog() << lor << LogIO::WARN << msg << LogIO::POST;
     379           0 :         this->addHistory(lor, msg);
     380           0 :         ImageUtilities::copyMiscellaneous(tmpIm, *subImage, false);
     381           0 :         auto info = subImage->imageInfo();
     382           0 :         auto beam = *(info.getBeamSet().getBeams().begin());
     383           0 :         info.removeRestoringBeam();
     384           0 :         info.setRestoringBeam(beam);
     385           0 :         tmpIm.setImageInfo(info);
     386           0 :         return true;
     387           0 :     }
     388           0 :     return false;
     389             : }
     390             : 
     391           0 : template<class T> void ImageCollapser<T>::_doOtherStats(
     392             :     TempImage<T>& tmpIm, SPCIIT subImage
     393             : ) const {
     394           0 :     T npixPerBeam = 1;
     395           0 :     if (_aggType == ImageCollapserData::SQRTSUM_NPIX_BEAM) {
     396           0 :         const auto& info = subImage->imageInfo();
     397           0 :         if (! info.hasBeam()) {
     398           0 :             *this->_getLog() << casacore::LogIO::WARN
     399             :                 << "Image has no beam, will use sqrtsum method"
     400           0 :                 << casacore::LogIO::POST;
     401             :         }
     402           0 :         else if (info.hasMultipleBeams()) {
     403           0 :             *this->_getLog() << casacore::LogIO::WARN
     404             :                 << "Function sqrtsum_npix_beam does not support multiple beams, will"
     405             :                 << "use sqrtsum method instead"
     406           0 :                 << casacore::LogIO::POST;
     407             :         }
     408             :         else {
     409           0 :             npixPerBeam = info.getBeamAreaInPixels(
     410           0 :                 -1, -1, subImage->coordinates().directionCoordinate()
     411             :             );
     412             :         }
     413             :     }
     414           0 :     _doLowPerf(tmpIm, subImage, npixPerBeam);
     415           0 : }
     416             : 
     417           0 : template<class T> void ImageCollapser<T>::_doLowPerf(
     418             :     TempImage<T>& tmpIm, SPCIIT subImage, T npixPerBeam
     419             : ) const {
     420             :     // flux or mask with one or more false values, must use lower performance methods
     421           0 :     auto lattStatType = _getStatsType();
     422           0 :     Array<T> data;
     423           0 :     Array<Bool> mask;
     424           0 :     if (_aggType == ImageCollapserData::FLUX) {
     425           0 :         ImageStatistics<T> stats(*subImage, false);
     426           0 :         stats.setAxes(_axes.asVector());
     427           0 :         if (
     428           0 :             ! stats.getConvertedStatistic(data, lattStatType, false)
     429             :         ) {
     430           0 :             ostringstream oss;
     431           0 :             oss << "Unable to calculate flux density: "
     432           0 :                 << stats.getMessages();
     433           0 :             ThrowCc(oss.str());
     434           0 :         }
     435           0 :         mask.resize(data.shape());
     436           0 :         mask.set(true);
     437           0 :     }
     438             :     else {
     439           0 :         LatticeMathUtil::collapse(
     440           0 :             data, mask, _axes, *subImage, false,
     441             :             true, true, lattStatType
     442             :         );
     443           0 :         if (
     444           0 :             _aggType == ImageCollapserData::SQRTSUM
     445           0 :             || _aggType == ImageCollapserData::SQRTSUM_NPIX
     446           0 :             || _aggType == ImageCollapserData::SQRTSUM_NPIX_BEAM
     447             :         ) {
     448           0 :             _zeroNegatives(data);
     449           0 :             data = sqrt(data);
     450           0 :             if (_aggType == ImageCollapserData::SQRTSUM_NPIX) {
     451           0 :                 auto npts = data.copy();
     452           0 :                 LatticeMathUtil::collapse(
     453           0 :                     npts, mask, _axes, *subImage, false,
     454             :                     true, true, LatticeStatsBase::NPTS
     455             :                 );
     456           0 :                 data /= npts;
     457           0 :             }
     458           0 :             else if (_aggType == ImageCollapserData::SQRTSUM_NPIX_BEAM) {
     459           0 :                 data /= npixPerBeam;
     460             :             }
     461             :         }
     462             :     }
     463           0 :     auto dataCopy = (_axes.size() <= 1)
     464           0 :         ? data : data.addDegenerate(_axes.size() - 1);
     465           0 :     IPosition newOrder(tmpIm.ndim(), -1);
     466           0 :     auto nAltered = _axes.size();
     467           0 :     auto nUnaltered = tmpIm.ndim() - nAltered;
     468           0 :     auto alteredCount = nUnaltered;
     469           0 :     auto unAlteredCount = 0;
     470           0 :     const auto ndim = tmpIm.ndim();
     471           0 :     const auto naxes = nAltered;
     472           0 :     for (uInt i = 0; i < ndim; ++i) {
     473           0 :         for (uInt j = 0; j < naxes; ++j) {
     474           0 :             if (i == _axes[j]) {
     475           0 :                 newOrder[i] = alteredCount;
     476           0 :                 alteredCount++;
     477           0 :                 break;
     478             :             }
     479             :         }
     480           0 :         if (newOrder[i] < 0) {
     481           0 :             newOrder[i] = unAlteredCount;
     482           0 :             ++unAlteredCount;
     483             :         }
     484             :     }
     485           0 :     tmpIm.put(reorderArray(dataCopy, newOrder));
     486           0 :     if (! allTrue(mask)) {
     487           0 :         auto maskCopy = (
     488           0 :             _axes.size() <= 1) ? mask
     489           0 :                 : mask.addDegenerate(_axes.size() - 1
     490             :         );
     491           0 :         auto mCopy = reorderArray(maskCopy, newOrder);
     492           0 :         tmpIm.attachMask(ArrayLattice<Bool>(mCopy));
     493           0 :     }
     494           0 : }
     495             : 
     496           0 : template<class T> LatticeStatsBase::StatisticsTypes ImageCollapser<T>::_getStatsType() const {
     497           0 :     auto lattStatType = LatticeStatsBase::NACCUM;
     498           0 :     switch (_aggType) {
     499           0 :     case ImageCollapserData::FLUX:
     500           0 :         lattStatType = LatticeStatsBase::FLUX;
     501           0 :         break;
     502           0 :     case ImageCollapserData::MAX:
     503           0 :         lattStatType = LatticeStatsBase::MAX;
     504           0 :         break;
     505           0 :     case ImageCollapserData::MEAN:
     506           0 :         lattStatType = LatticeStatsBase::MEAN;
     507           0 :         break;
     508           0 :     case ImageCollapserData::MIN:
     509           0 :         lattStatType = LatticeStatsBase::MIN;
     510           0 :         break;
     511           0 :     case ImageCollapserData::NPTS:
     512           0 :         lattStatType = LatticeStatsBase::NPTS;
     513           0 :         break;
     514           0 :     case ImageCollapserData::RMS:
     515           0 :         lattStatType = LatticeStatsBase::RMS;
     516           0 :         break;
     517           0 :     case ImageCollapserData::STDDEV:
     518           0 :         lattStatType = LatticeStatsBase::SIGMA;
     519           0 :         break;
     520           0 :     case ImageCollapserData::SQRTSUM:
     521             :     case ImageCollapserData::SQRTSUM_NPIX:
     522             :     case ImageCollapserData::SQRTSUM_NPIX_BEAM:
     523             :     case ImageCollapserData::SUM:
     524           0 :         lattStatType = LatticeStatsBase::SUM;
     525           0 :         break;
     526           0 :     case ImageCollapserData::VARIANCE:
     527           0 :         lattStatType = LatticeStatsBase::VARIANCE;
     528           0 :         break;
     529           0 :     case ImageCollapserData::MEDIAN:
     530             :     case ImageCollapserData::ZERO:
     531             :     case ImageCollapserData::UNKNOWN:
     532             :     default:
     533           0 :         ThrowCc(
     534             :             "Logic error. Should never have gotten the the bottom of the switch statement"
     535             :         );
     536             :         break;
     537             :     }
     538           0 :     return lattStatType;
     539             : }
     540             : 
     541           0 : template<class T> void ImageCollapser<T>::_zeroNegatives(Array<T>& arr) {
     542           0 :     auto iter = arr.begin();
     543           0 :     if (isComplex(whatType<T>()) || allGE(arr, (T)0)) {
     544           0 :         return;
     545             :     }
     546           0 :     auto end = arr.end();
     547           0 :     for (; iter != end; ++iter) {
     548           0 :         if (*iter < 0) {
     549           0 :             *iter = 0;
     550             :         }
     551             :     }
     552           0 : }
     553             : 
     554           0 : template<class T> void ImageCollapser<T>::_finishConstruction() {
     555           0 :     for (
     556           0 :         casacore::IPosition::const_iterator iter = _axes.begin();
     557           0 :         iter != _axes.end(); iter++
     558             :     ) {
     559           0 :         ThrowIf(
     560             :             *iter >= this->_getImage()->ndim(),
     561             :             "Specified zero-based axis (" + casacore::String::toString(*iter)
     562             :             + ") must be less than the number of axes in " + this->_getImage()->name()
     563             :             + "(" + casacore::String::toString(this->_getImage()->ndim()) + ")"
     564             :         );
     565             :     }
     566           0 :     _invert();
     567           0 : }
     568             : 
     569           0 : template<class T> void ImageCollapser<T>::_invert() {
     570           0 :     if (_invertAxesSelection) {
     571           0 :         casacore::IPosition x = casacore::IPosition::otherAxes(this->_getImage()->ndim(), _axes);
     572           0 :         _axes.resize(x.size());
     573           0 :         _axes = x;
     574           0 :     }
     575           0 : }
     576             : 
     577             : }

Generated by: LCOV version 1.16