LCOV - code coverage report
Current view: top level - imageanalysis/ImageAnalysis - ImageTask.tcc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 30 218 13.8 %
Date: 2024-12-11 20:54:31 Functions: 3 21 14.3 %

          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             : //# $Id: $
      26             : 
      27             : #include <imageanalysis/ImageAnalysis/ImageTask.h>
      28             : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
      29             : #include <casacore/casa/IO/FilebufIO.h>
      30             : #include <casacore/casa/OS/Directory.h>
      31             : #include <casacore/casa/OS/RegularFile.h>
      32             : #include <casacore/casa/OS/SymLink.h>
      33             : #include <casacore/images/Images/FITSImage.h>
      34             : #include <casacore/images/Images/ImageUtilities.h>
      35             : #include <casacore/images/Images/MIRIADImage.h>
      36             : #include <casacore/images/Images/PagedImage.h>
      37             : #include <casacore/images/Images/TempImage.h>
      38             : #include <casacore/tables/Tables/PlainTable.h>
      39             : 
      40             : #include <imageanalysis/ImageAnalysis/ImageHistory.h>
      41             : #include <imageanalysis/ImageAnalysis/ImageInputProcessor.h>
      42             : #include <imageanalysis/ImageAnalysis/ImageMask.h>
      43             : #include <imageanalysis/ImageAnalysis/SubImageFactory.h>
      44             : #include <imageanalysis/IO/LogFile.h>
      45             : #include <stdcasa/variant.h>
      46             : 
      47             : namespace casa {
      48             : 
      49           0 : template <class T> ImageTask<T>::ImageTask(
      50             :     const SPCIIT image,
      51             :     const casacore::String& region, const casacore::Record *const &regionPtr,
      52             :     const casacore::String& box, const casacore::String& chanInp,
      53             :     const casacore::String& stokes, const casacore::String& maskInp,
      54             :     const casacore::String& outname, casacore::Bool overwrite
      55           0 : ) : _image(image), _regionPtr(regionPtr),_region(region), _box(box),
      56           0 :     _chan(chanInp), _stokesString(stokes), _mask(maskInp),
      57           0 :     _outname(outname), _overwrite(overwrite), _stretch(false),
      58           0 :     _logfile() {}
      59             : 
      60           0 : template <class T> ImageTask<T>::ImageTask(
      61             :     const SPCIIT image, const casacore::Record *const &regionPtr,
      62             :     const casacore::String& mask, const casacore::String& outname,
      63             :     casacore::Bool overwrite
      64           0 : ) : _image(image), _regionPtr(regionPtr),
      65           0 :     _region(), _box(), _chan(), _stokesString(), _mask(mask),
      66           0 :     _outname(outname), _overwrite(overwrite) {}
      67             : 
      68           0 : template <class T> ImageTask<T>::~ImageTask() {}
      69             : 
      70           0 : template <class T> std::vector<OutputDestinationChecker::OutputStruct> ImageTask<T>::_getOutputStruct() {
      71           0 :     std::vector<OutputDestinationChecker::OutputStruct> outputs;
      72           0 :     _outname.trim();
      73           0 :     if (! _outname.empty()) {
      74           0 :         OutputDestinationChecker::OutputStruct outputImage;
      75           0 :         outputImage.label = "output image";
      76           0 :         outputImage.outputFile = &_outname;
      77           0 :         outputImage.required = true;
      78           0 :         outputImage.replaceable = _overwrite;
      79           0 :         outputs.push_back(outputImage);
      80           0 :     }
      81           0 :     return outputs;
      82           0 : }
      83             : 
      84           0 : template <class T> void ImageTask<T>::_construct(casacore::Bool verbose) {
      85           0 :     ThrowIf(
      86             :         ! _supportsMultipleBeams() && _image->imageInfo().hasMultipleBeams(),
      87             :         "This application does not support images with multiple "
      88             :         "beams. Please convolve your image with a single beam "
      89             :         "and run this application using that image"
      90             :     );
      91           0 :     casacore::String diagnostics;
      92           0 :     std::vector<OutputDestinationChecker::OutputStruct> outputs = _getOutputStruct();
      93           0 :     std::vector<OutputDestinationChecker::OutputStruct> *outputPtr = outputs.size() > 0
      94           0 :         ? &outputs
      95             :         : 0;
      96           0 :     std::vector<casacore::Coordinate::Type> necCoords = _getNecessaryCoordinates();
      97           0 :     std::vector<casacore::Coordinate::Type> *coordsPtr = necCoords.size() > 0
      98           0 :         ? &necCoords
      99             :         : 0;
     100           0 :     ThrowIf(
     101             :         _mustHaveSquareDirectionPixels()
     102             :         && _image->coordinates().hasDirectionCoordinate()
     103             :         && ! _image->coordinates().directionCoordinate().hasSquarePixels(),
     104             :         "This application requires that the input image must have square "
     105             :         "direction pixels, but the input image does not. Please regrid it "
     106             :         "so it does and rerun on the regridded image"
     107             :     );
     108           0 :     ImageInputProcessor inputProcessor;
     109           0 :     inputProcessor.process(
     110           0 :         _regionRecord, diagnostics, outputPtr,
     111           0 :         _stokesString, _image, _regionPtr,
     112           0 :         _region, _box, _chan,
     113           0 :         _getStokesControl(), _supportsMultipleRegions(),
     114             :         coordsPtr, verbose
     115             :     );
     116           0 : }
     117             : 
     118             : template <class T> void ImageTask<T>::setRegion(const casacore::Record& region) {
     119             :     ThrowIf(
     120             :         ! _supportsMultipleRegions() && region.isDefined("regions"),
     121             :         "This application does not support multiple region selection"
     122             :     );
     123             :     _regionRecord = region;
     124             :     _box = "";
     125             :     _chan = "";
     126             :     _stokesString = "";
     127             :     _region = "";
     128             : }
     129             : 
     130           0 : template <class T> void ImageTask<T>::_removeExistingFileIfNecessary(
     131             :     const casacore::String& filename, casacore::Bool overwrite, casacore::Bool warnOnly
     132             : ) const {
     133           0 :     casacore::File out(filename);
     134           0 :     if (out.exists()) {
     135           0 :         if (overwrite) {
     136           0 :             File f(filename);
     137           0 :             ThrowIf(
     138             :                 PlainTable::tableCache()(f.path().absoluteName()),
     139             :                 filename + " is currently present in the table cache "
     140             :                 + "and so is being used by another process. Please close "
     141             :                 + "it in the other process first before attempting to "
     142             :                 + "overwrite it"
     143             :             );
     144           0 :             if (out.isDirectory()) {
     145           0 :                 casacore::Directory dir(filename);
     146           0 :                 dir.removeRecursive();
     147           0 :             }
     148           0 :             else if (out.isRegular()) {
     149           0 :                 casacore::RegularFile reg(filename);
     150           0 :                 reg.remove();
     151           0 :             }
     152           0 :             else if (out.isSymLink()) {
     153           0 :                 casacore::SymLink link(filename);
     154           0 :                 link.remove();
     155           0 :             }
     156           0 :         }
     157             :         else {
     158           0 :             casacore::String msg = "File " + filename + " exists but overwrite is false "
     159             :                 "so it cannot be overwritten";
     160           0 :             if (warnOnly) {
     161           0 :                 *_log << casacore::LogIO::WARN << msg << casacore::LogIO::POST;
     162             :             }
     163             :             else {
     164           0 :                 ThrowCc(msg);
     165             :             }
     166           0 :         }
     167             :     }
     168           0 : }
     169             : 
     170             : template <class T> void ImageTask<T>::_removeExistingOutfileIfNecessary() const {
     171             :     _removeExistingFileIfNecessary(_outname, _overwrite);
     172             : }
     173             : 
     174          86 : template <class T> casacore::String ImageTask<T>::_summaryHeader() const {
     175          86 :     casacore::String region = _box.empty() ? _region : "";
     176          86 :     ostringstream os;
     177          86 :     os << "Input parameters ---" << endl;
     178          86 :     os << "       --- imagename:           " << _image->name() << endl;
     179          86 :     os << "       --- region:              " << region << endl;
     180          86 :     os << "       --- box:                 " << _box << endl;
     181          86 :     os << "       --- channels:            " << _chan << endl;
     182          86 :     os << "       --- stokes:              " << _stokesString << endl;
     183          86 :     os << "       --- mask:                " << _mask << endl;
     184         172 :     return os.str();
     185          86 : }
     186             : 
     187             : template <class T> void ImageTask<T>::setLogfile(const casacore::String& lf) {
     188             :     if (lf.empty()) {
     189             :         return;
     190             :     }
     191             :     ThrowIf(
     192             :         ! _hasLogfileSupport(),
     193             :         "Logic Error: This task does not support writing of a log file"
     194             :     );
     195             :     try {
     196             :         _logfile.reset(new LogFile(lf));
     197             :         _logfile->setAppend(_logfileAppend);
     198             :     }
     199             :     catch (const casacore::AipsError& x) {}
     200             : }
     201             : 
     202           0 : template <class T> const std::shared_ptr<LogFile> ImageTask<T>::_getLogFile() const {
     203           0 :     ThrowIf(
     204             :         ! _hasLogfileSupport(),
     205             :         "Logic Error: This task does not support writing of a log file"
     206             :     );
     207           0 :     return _logfile;
     208             : }
     209             : 
     210             : template <class T> casacore::Bool ImageTask<T>::_openLogfile() {
     211             :     if (_logfile.get() == 0) {
     212             :         return false;
     213             :     }
     214             :     ThrowIf(
     215             :         ! _hasLogfileSupport(),
     216             :         "Logic Error: This task does not support writing of a log file"
     217             :     );
     218             :     return _logfile->open();
     219             : }
     220             : 
     221             : template <class T> void ImageTask<T>::_closeLogfile() const {
     222             :     if (_logfile) {
     223             :         _logfile->close();
     224             :     }
     225             : }
     226             : 
     227             : template<class T> casacore::Bool ImageTask<T>::_writeLogfile(
     228             :     const casacore::String& output, const casacore::Bool open, const casacore::Bool close
     229             : ) {
     230             :     ThrowIf(
     231             :         ! _hasLogfileSupport(),
     232             :         "Logic Error: This task does not support writing of a log file"
     233             :     );
     234             :     if (! _logfile) {
     235             :         return false;
     236             :     }
     237             :     return _logfile->write(output, open, close);
     238             : }
     239             : 
     240             : template <class T> void ImageTask<T>::setLogfileAppend(casacore::Bool a) {
     241             :     ThrowIf(
     242             :         ! _hasLogfileSupport(),
     243             :         "Logic Error: This task does not support writing of a log file"
     244             :     );
     245             :     _logfileAppend = a;
     246             :     if (_logfile) {
     247             :         _logfile->setAppend(a);
     248             :     }
     249             : }
     250             : 
     251           0 : template <class T> void ImageTask<T>::addHistory(
     252             :     const vector<std::pair<casacore::String, casacore::String> >& msgs
     253             : ) const {
     254           0 :     _newHistory.insert(
     255           0 :         _newHistory.end(), msgs.begin(), msgs.end()
     256             :     );
     257           0 : }
     258             : 
     259           0 : template <class T> void ImageTask<T>::addHistory(
     260             :     const casacore::LogOrigin& origin, const casacore::String& msg
     261             : ) const {
     262           0 :     std::pair<casacore::String, casacore::String> x;
     263           0 :     x.first = origin.fullName();
     264           0 :     x.second = msg;
     265           0 :     _newHistory.push_back(x);
     266           0 : }
     267             : 
     268           0 : template <class T> void ImageTask<T>::addHistory(
     269             :     const casacore::LogOrigin& origin, const vector<casacore::String>& msgs
     270             : ) const {
     271           0 :     std::pair<casacore::String, casacore::String> x;
     272           0 :     x.first = origin.fullName();
     273           0 :     for( casacore::String m: msgs ) {
     274           0 :         x.second = m;
     275           0 :         _newHistory.push_back(x);
     276             :     }
     277           0 : }
     278             : 
     279             : template <class T> void ImageTask<T>::addHistory(
     280             :     const casacore::LogOrigin& origin, const casacore::String& taskname,
     281             :     const vector<casacore::String>& paramNames, const vector<casac::variant>& paramValues
     282             : ) const {
     283             :     auto appHistory = ImageHistory<T>::getApplicationHistory(
     284             :         origin, taskname, paramNames, paramValues, _image->name()
     285             :     );
     286             :     _newHistory.insert(_newHistory.end(), appHistory.begin(), appHistory.end());
     287             : }
     288             : 
     289           0 : template <class T> void ImageTask<T>::_copyMask(
     290             :     casacore::Lattice<casacore::Bool>& mask, const casacore::ImageInterface<T>& image
     291             : ) {
     292           0 :     auto cursorShape = image.niceCursorShape(4096*4096);
     293           0 :     casacore::LatticeStepper stepper(image.shape(), cursorShape, casacore::LatticeStepper::RESIZE);
     294           0 :     casacore::RO_MaskedLatticeIterator<T> iter(image, stepper);
     295           0 :     casacore::LatticeIterator<casacore::Bool> miter(mask, stepper);
     296           0 :     std::unique_ptr<casacore::RO_LatticeIterator<casacore::Bool>> pmiter;
     297           0 :     if (image.hasPixelMask()) {
     298           0 :         pmiter.reset(new casacore::RO_LatticeIterator<casacore::Bool>(image.pixelMask(), stepper));
     299             :     }
     300           0 :     for (iter.reset(); ! iter.atEnd(); ++iter, ++miter) {
     301           0 :         auto mymask = iter.getMask();
     302           0 :         if (pmiter) {
     303           0 :             mymask = mymask && pmiter->cursor();
     304           0 :             pmiter->operator++();
     305             :         }
     306           0 :         miter.rwCursor() = mymask;
     307             :     }
     308           0 : }
     309             : 
     310           0 : template <class T> void ImageTask<T>::_copyData(
     311             :     Lattice<T>& data, const Lattice<T>& image
     312             : ) {
     313           0 :     auto cursorShape = image.niceCursorShape(4096*4096);
     314           0 :     casacore::LatticeStepper stepper(image.shape(), cursorShape, casacore::LatticeStepper::RESIZE);
     315           0 :     casacore::RO_LatticeIterator<T> iter(image, stepper);
     316           0 :     casacore::LatticeIterator<T> diter(data, stepper);
     317           0 :     for (iter.reset(); ! iter.atEnd(); ++iter, ++diter) {
     318           0 :         diter.rwCursor() = iter.cursor();
     319             :     }
     320           0 : }
     321             : 
     322           0 : template <class T> casacore::Bool ImageTask<T>::_isPVImage() const {
     323           0 :     const CoordinateSystem& csys = _image->coordinates();
     324           0 :     if (csys.hasLinearCoordinate() && csys.hasSpectralAxis()) {
     325           0 :         auto pixelAxes = csys.linearAxesNumbers();
     326           0 :         auto nPixelAxes = pixelAxes.size();
     327           0 :         auto names = csys.worldAxisNames();
     328           0 :         for (uInt j=0; j<nPixelAxes; ++j) {
     329           0 :             if (pixelAxes[j] >= 0 && names[pixelAxes[j]] == "Offset") {
     330           0 :                 return true;
     331             :             }
     332             :         }
     333           0 :     }
     334           0 :     return false;
     335             : }
     336             : 
     337           0 : template <class T> SPIIT ImageTask<T>::_prepareOutputImage(
     338             :     const casacore::ImageInterface<T>& image, const casacore::Array<T> *const values,
     339             :     const casacore::ArrayLattice<casacore::Bool> *const mask,
     340             :     const casacore::IPosition *const outShape, const casacore::CoordinateSystem *const coordsys,
     341             :     const casacore::String *const outname, casacore::Bool overwrite, casacore::Bool dropDegen
     342             : ) const {
     343           0 :     auto oShape = outShape == 0 ? image.shape() : *outShape;
     344           0 :     casacore::CoordinateSystem csys = coordsys ? *coordsys : image.coordinates();
     345           0 :     std::shared_ptr<casacore::TempImage<T>> tmpImage(
     346           0 :         new casacore::TempImage<T>(casacore::TiledShape(oShape), csys)
     347             :     );
     348           0 :     if (mask && (! ImageMask::isAllMaskTrue(*mask))) {
     349           0 :         tmpImage->attachMask(*mask);
     350             :     }
     351             :     // because subimages can have two types of masks, a region mask and
     352             :     // a pixel mask, but most other types of images really just have a
     353             :     // pixel mask. its very confusing
     354           0 :     else if (image.hasPixelMask() || image.isMasked()) {
     355             :         // A paged array is stored on disk and is preferred over an
     356             :         // ArrayLattice which will exhaust memory for large images.
     357           0 :         std::unique_ptr<casacore::Lattice<casacore::Bool>> mymask;
     358             :         const static auto mmasksize = 4096*4096;
     359           0 :         if (image.size() > mmasksize) {
     360           0 :             mymask.reset(new casacore::PagedArray<casacore::Bool>(image.shape()));
     361             :         }
     362             :         else {
     363           0 :             mymask.reset(new casacore::ArrayLattice<casacore::Bool>(image.shape()));
     364             :         }
     365           0 :         _copyMask(*mymask, image);
     366           0 :         if (! ImageMask::isAllMaskTrue(image)) {
     367           0 :             tmpImage->attachMask(*mymask);
     368             :         }
     369           0 :     }
     370           0 :     auto myOutname = outname ? *outname : _outname;
     371           0 :     if (! outname) {
     372           0 :         overwrite = _overwrite;
     373             :     }
     374           0 :     SPIIT outImage = tmpImage;
     375           0 :     if (values) {
     376           0 :         outImage->put(*values);
     377             :     }
     378             :     else {
     379             :         // FIXME this is a superfluous copy if  dropgen || ! myOutname.empty()
     380           0 :         _copyData(*outImage, image);
     381             :     }
     382           0 :     if (dropDegen || ! myOutname.empty()) {
     383           0 :         if (! myOutname.empty()) {
     384           0 :             _removeExistingFileIfNecessary(myOutname, overwrite);
     385             :         }
     386           0 :         casacore::String emptyMask = "";
     387           0 :         casacore::Record empty;
     388           0 :         outImage = SubImageFactory<T>::createImage(
     389           0 :             *tmpImage, myOutname, empty, emptyMask,
     390             :             dropDegen, false, true, false
     391             :         );
     392           0 :     }
     393           0 :     casacore::ImageUtilities::copyMiscellaneous(*outImage, image);
     394           0 :     _doHistory(outImage);
     395             :     // CAS-9267 force metadata to be written to disk, in case of PagedImage
     396           0 :     outImage->flush();
     397           0 :     return outImage;
     398           0 : }
     399             : 
     400           0 : template <class T> SPIIT ImageTask<T>::_prepareOutputImage(
     401             :     const casacore::ImageInterface<T>& image, casacore::Bool dropDeg
     402             : ) const {
     403           0 :     if (! _outname.empty()) {
     404           0 :         _removeExistingFileIfNecessary(_outname, _overwrite);
     405             :     }
     406           0 :     static const casacore::Record empty;
     407           0 :     static const casacore::String emptyString;
     408           0 :     auto outImage = SubImageFactory<T>::createImage(
     409           0 :         image, _outname, empty, emptyString, dropDeg,
     410           0 :         _overwrite, true, false, false
     411             :     );
     412           0 :     _doHistory(outImage);
     413           0 :     return outImage;
     414           0 : }
     415             : 
     416          58 : template <class T> SPIIT ImageTask<T>::_prepareOutputImage(
     417             :     const casacore::ImageInterface<T>& image, const casacore::String& outname,
     418             :     casacore::Bool overwrite, casacore::Bool warnOnly
     419             : ) const {
     420          58 :     if (! outname.empty()) {
     421          58 :         _removeExistingFileIfNecessary(outname, overwrite, warnOnly);
     422             :     }
     423          58 :     static const casacore::Record empty;
     424          58 :     static const casacore::String emptyString;
     425          58 :     auto outImage = SubImageFactory<T>::createImage(
     426             :         image, outname, empty, emptyString, false,
     427             :         overwrite, true, false, false
     428             :     );
     429          58 :     _doHistory(outImage);
     430          58 :     return outImage;
     431           0 : }
     432             : 
     433             : 
     434          14 : template <class T> SPIIT ImageTask<T>::_prepareOutputImage(
     435             :     const casacore::ImageInterface<T>& image, const casacore::Lattice<T>& data
     436             : ) const {
     437          14 :     if (! _outname.empty()) {
     438          14 :         _removeExistingFileIfNecessary(_outname, _overwrite);
     439             :     }
     440          14 :     static const casacore::Record empty;
     441          14 :     static const casacore::String emptyString;
     442          14 :     auto outImage = SubImageFactory<T>::createImage(
     443          14 :         image, _outname, empty, emptyString, false,
     444          14 :         _overwrite, true, false, false, &data
     445             :     );
     446          14 :     _doHistory(outImage);
     447          14 :     return outImage;
     448           0 : }
     449             : 
     450             : template <class T>
     451           0 : template <class U> void ImageTask<T>::_doHistory(std::shared_ptr<casacore::ImageInterface<U>>& image) const {
     452           0 :     if (! _suppressHistory) {
     453           0 :         ImageHistory<U> history(image);
     454           0 :         if (history.get(false).empty()) {
     455           0 :             history.append(_image);
     456             :         }
     457           0 :         history.addHistory(_newHistory);
     458             :         /*
     459             :         for (const auto& line: _newHistory) {
     460             :             history.addHistory(line.first, line.second);
     461             :         }
     462             :         */
     463           0 :     }
     464           0 : }
     465             : 
     466           0 : template <class T> void ImageTask<T>::_reportOldNewImageShapes(const IPosition& outShape) const {
     467           0 :     LogOrigin lor(getClass(), __func__);
     468           0 :     ostringstream os;
     469           0 :     os << "Original " << _getImage()->name() << " size => "
     470           0 :         << _getImage()->shape();
     471           0 :     addHistory(lor, os.str());
     472           0 :     *_getLog() << LogIO::NORMAL << os.str() << LogIO::POST;
     473           0 :     os.str("");
     474           0 :     os << "New " << _getOutname() << " size => " << outShape;
     475           0 :     addHistory(lor, os.str());
     476           0 :     *_getLog() << LogIO::NORMAL << os.str() << LogIO::POST;
     477           0 : }
     478             : 
     479             : template <class T> void ImageTask<T>::_reportOldNewImageShapes(const ImageInterface<T>& out) const {
     480             :     _reportOldNewImageShapes(out.shape());
     481             : }
     482             : 
     483             : }
     484             : 

Generated by: LCOV version 1.16