LCOV - code coverage report
Current view: top level - synthesis/ImagerObjects - SIImageStore.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 842 1731 48.6 %
Date: 2025-07-23 00:22:00 Functions: 62 103 60.2 %

          Line data    Source code
       1             : //# SIImageStore.cc: Implementation of Imager.h
       2             : //# Copyright (C) 1997-2008
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This program is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU General Public License as published by the Free
       7             : //# Software Foundation; either version 2 of the License, or (at your option)
       8             : //# any later version.
       9             : //#
      10             : //# This program is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      13             : //# more details.
      14             : //#
      15             : //# You should have received a copy of the GNU General Public License along
      16             : //# with this program; if not, write to the Free Software Foundation, Inc.,
      17             : //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id$
      27             : 
      28             : #include <casacore/casa/Exceptions/Error.h>
      29             : #include <iostream>
      30             : #include <sstream>
      31             : 
      32             : #include <casacore/casa/Arrays/Matrix.h>
      33             : #include <casacore/casa/Arrays/ArrayMath.h>
      34             : #include <casacore/casa/Arrays/ArrayLogical.h>
      35             : 
      36             : #include <casacore/casa/Logging.h>
      37             : #include <casacore/casa/Logging/LogIO.h>
      38             : #include <casacore/casa/Logging/LogMessage.h>
      39             : #include <casacore/casa/Logging/LogSink.h>
      40             : #include <casacore/casa/Logging/LogMessage.h>
      41             : #include <casacore/casa/OS/DirectoryIterator.h>
      42             : #include <casacore/casa/OS/File.h>
      43             : #include <casacore/casa/OS/Path.h>
      44             : #include <casacore/lattices/Lattices/LatticeLocker.h>
      45             : #include <casacore/casa/OS/HostInfo.h>
      46             : #include <components/ComponentModels/GaussianDeconvolver.h>
      47             : #include <casacore/images/Images/TempImage.h>
      48             : #include <casacore/images/Images/PagedImage.h>
      49             : #include <imageanalysis/ImageAnalysis/CasaImageBeamSet.h>
      50             : #include <casacore/lattices/LatticeMath/LatticeMathUtil.h>
      51             : #include <casacore/ms/MeasurementSets/MSHistoryHandler.h>
      52             : #include <casacore/ms/MeasurementSets/MeasurementSet.h>
      53             : #include <casacore/tables/Tables/TableUtil.h>
      54             : 
      55             : #include <synthesis/ImagerObjects/SIImageStore.h>
      56             : #include <synthesis/ImagerObjects/SDMaskHandler.h>
      57             : #include <synthesis/TransformMachines/StokesImageUtil.h>
      58             : #include <synthesis/TransformMachines2/Utils.h>
      59             : #include <synthesis/ImagerObjects/SynthesisUtilMethods.h>
      60             : #include <casacore/images/Images/ImageRegrid.h>
      61             : #include <imageanalysis/ImageAnalysis/ImageStatsCalculator.h>
      62             : 
      63             : //#include <imageanalysis/ImageAnalysis/ImageMaskedPixelReplacer.h>
      64             : 
      65             : #include <sys/types.h>
      66             : #include <unistd.h>
      67             : #include "SIImageStore.h"
      68             : using namespace std;
      69             : 
      70             : using namespace casacore;
      71             : 
      72             : namespace casa { //# NAMESPACE CASA - BEGIN
      73             : 
      74             :   //
      75             :   //===========================================================================
      76             :   // Global method that I (SB) could make work in SynthesisUtilsMethods.
      77             :   //
      78             :   template <class T>
      79           0 :   void openImage(const String& imagenamefull,std::shared_ptr<ImageInterface<T> >& imPtr )
      80             :   {
      81           0 :     LogIO logIO ( LogOrigin("SynthesisImager","openImage(name)") );
      82             :     try
      83             :       {
      84           0 :         if (Table::isReadable(imagenamefull))
      85           0 :           imPtr.reset( new PagedImage<T>( imagenamefull ) );
      86             :       }
      87           0 :     catch (AipsError &x)
      88             :       {
      89           0 :         logIO << "Error in reading image \"" << imagenamefull << "\"" << LogIO::EXCEPTION;
      90             :       }
      91           0 :   }
      92             :   //
      93             :   //--------------------------------------------------------------
      94             :   //
      95             :   template 
      96             :   void openImage(const String& imagenamefull, std::shared_ptr<ImageInterface<Float> >& img );
      97             :   template 
      98             :   void openImage(const String& imagenamefull, std::shared_ptr<ImageInterface<Complex> >& img );
      99             :   //
     100             :   //===========================================================================
     101             : 
     102             : 
     103             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     104             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     105             :   /////       START of SIIMAGESTORE implementation
     106             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     107             : 
     108             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     109             :   
     110          58 :   SIImageStore::SIImageStore()
     111             :   {
     112             :       
     113          58 :     itsPsf.reset( );
     114          58 :     itsModel.reset( );
     115          58 :     itsResidual.reset( );
     116          58 :     itsWeight.reset( );
     117          58 :     itsImage.reset( );
     118          58 :     itsMask.reset( );
     119          58 :     itsGridWt.reset( );
     120          58 :     itsPB.reset( );
     121          58 :     itsImagePBcor.reset();
     122          58 :     itsTempWorkIm.reset();
     123             : 
     124          58 :     itsSumWt.reset( );
     125          58 :     itsOverWrite = False;
     126          58 :     itsUseWeight = False;
     127          58 :     itsPBScaleFactor = 1.0;
     128             : 
     129          58 :     itsNFacets = 1;
     130          58 :     itsFacetId = 0;
     131          58 :     itsNChanChunks = 1;
     132          58 :     itsChanId = 0;
     133          58 :     itsNPolChunks = 1;
     134          58 :     itsPolId = 0;
     135             : 
     136          58 :     itsImageShape = IPosition(4,0,0,0,0);
     137          58 :     itsImageName = String("");
     138          58 :     itsCoordSys = CoordinateSystem();
     139          58 :     itsMiscInfo = Record();
     140             : 
     141          58 :     itsIsSingleDishStore = False;
     142             : 
     143          58 :     init();
     144             :     //    validate();
     145             : 
     146          58 :   }
     147             : 
     148             :   // Used from SynthesisNormalizer::makeImageStore()
     149          13 :   SIImageStore::SIImageStore(
     150             :     const String &imagename,
     151             :     const CoordinateSystem &imcoordsys,
     152             :     const IPosition &imshape,
     153             :     const String &objectname,
     154             :     const Record &miscinfo,
     155             :     //  const Int nfacets,
     156             :     const Bool /*overwrite*/,
     157             :     const Bool useweightimage,
     158             :     const Bool issingledishstore
     159          13 :   )
     160             :   // TODO : Add parameter to indicate weight image shape. 
     161             :   {
     162          26 :     LogIO os( LogOrigin("SIImageStore","Open new Images",WHERE) );
     163             :       
     164             : 
     165          13 :     itsPsf.reset( );
     166          13 :     itsModel.reset( );
     167          13 :     itsResidual.reset( );
     168          13 :     itsWeight.reset( );
     169          13 :     itsImage.reset( );
     170          13 :     itsMask.reset( );
     171          13 :     itsGridWt.reset( );
     172          13 :     itsPB.reset( );
     173          13 :     itsImagePBcor.reset( );
     174          13 :     itsTempWorkIm.reset();
     175             : 
     176          13 :     itsSumWt.reset( );
     177          13 :     itsOverWrite = False; // Hard Coding this. See CAS-6937. overwrite;
     178          13 :     itsUseWeight = useweightimage;
     179          13 :     itsPBScaleFactor = 1.0;
     180             : 
     181          13 :     itsNFacets = 1;
     182          13 :     itsFacetId = 0;
     183          13 :     itsNChanChunks = 1;
     184          13 :     itsChanId = 0;
     185          13 :     itsNPolChunks = 1;
     186          13 :     itsPolId = 0;
     187             : 
     188          13 :     itsImageName = imagename;
     189          13 :     itsCoordSys = imcoordsys;
     190          13 :     itsImageShape = imshape;
     191          13 :     itsObjectName = objectname;
     192          13 :     itsMiscInfo = miscinfo;
     193             : 
     194          13 :     itsIsSingleDishStore = issingledishstore;
     195             : 
     196          13 :     init();
     197             : 
     198          13 :     validate();
     199          13 :   }
     200             : 
     201             :   // Used from SynthesisNormalizer::makeImageStore()
     202             :   // This constructor creates an Image Store from images on disk
     203          19 :   SIImageStore::SIImageStore(
     204             :     const String &imagename,
     205             :     const Bool ignorefacets,
     206             :     const Bool noRequireSumwt,
     207          19 :     const Bool makeSingleDishStore)
     208             :   {
     209          38 :     LogIO os( LogOrigin("SIImageStore","Open existing Images",WHERE) );
     210             : 
     211             :     { // Initialize some members
     212          19 :       itsImageName = imagename;
     213             : 
     214          19 :       itsPsf.reset( );
     215          19 :       itsModel.reset( );
     216          19 :       itsResidual.reset( );
     217          19 :       itsWeight.reset( );   
     218          19 :       itsImage.reset( );
     219          19 :       itsMask.reset( );
     220          19 :       itsGridWt.reset( );
     221          19 :       itsPB.reset( );
     222          19 :       itsImagePBcor.reset( );
     223          19 :       itsTempWorkIm.reset();
     224          19 :       itsMiscInfo = Record();
     225             : 
     226          19 :       itsSumWt.reset( );
     227          19 :       itsNFacets = 1;
     228          19 :       itsFacetId = 0;
     229          19 :       itsNChanChunks = 1;
     230          19 :       itsChanId = 0;
     231          19 :       itsNPolChunks = 1;
     232          19 :       itsPolId = 0;
     233             :     
     234          19 :       itsOverWrite = False;
     235             : 
     236          19 :       itsIsSingleDishStore = makeSingleDishStore;
     237             :     }
     238             : 
     239             :     // Need to do this init now so that imageExts is initialized
     240          19 :     init();
     241             : 
     242             :     // Since this constructor creates an ImStore from images on disk,
     243             :     // it needs at least one of the images to actually be present on disk,
     244             :     // from which it can retrieve shape and coordsys information.
     245             : 
     246             :     { // Do we have at least 1 usable image ?
     247          19 :       constexpr SIImageStore::IMAGE_IDS imageIds[] = {
     248             :         SIImageStore::PSF,
     249             :         SIImageStore::RESIDUAL,
     250             :         SIImageStore::MODEL,
     251             :         SIImageStore::PB,
     252             :         SIImageStore::WEIGHT,
     253             :         SIImageStore::GRIDWT,
     254             :       };
     255             :   
     256          19 :       std::shared_ptr<ImageInterface<Float> > imptr;
     257             : 
     258          19 :       auto haveImage = False;
     259          26 :       for (auto imageId : imageIds) {
     260          26 :         const auto imageName = imageFullName(imageId);
     261          26 :         if (doesImageExist(imageName)) {
     262          19 :           if (imageId == SIImageStore::GRIDWT) {
     263           0 :             constexpr auto preserveOldComment = True;
     264             :             // How can this be right ?
     265             :           }
     266          19 :           buildImage(imptr, imageName);
     267          19 :           haveImage = True;
     268          19 :           break;
     269             :         }
     270          26 :       }
     271             : 
     272          19 :       if (haveImage) {
     273          19 :         itsObjectName = imptr->imageInfo().objectName();
     274          19 :         itsImageShape = imptr->shape();
     275          19 :         itsCoordSys = imptr->coordinates();
     276          19 :         itsMiscInfo = imptr->miscInfo();
     277             :       } else {
     278           0 :         String errMsg;
     279           0 :         if (not itsIsSingleDishStore) {
     280             :           errMsg = "PSF, Residual, Model Image (or sumwt) do not exist."
     281           0 :                   " Please create one of them.";
     282             :         } else {
     283           0 :           errMsg = String("Single-dish image and single-dish weight image"
     284             :                    " do not exist. Please create one of:\n")
     285           0 :                    + imageFullName(SIImageStore::RESIDUAL) + "\nor\n"
     286           0 :                    + imageFullName(SIImageStore::WEIGHT);
     287             :         }
     288           0 :         throw AipsError(errMsg);
     289           0 :       }
     290          19 :     }
     291             : 
     292             :     { // Handle special case: psf or residual exist
     293             :       // Should we update things here when itsIsSingleDishStore = True ?
     294          19 :       if (    doesImageExist( imageFullName(RESIDUAL) )
     295          19 :            or doesImageExist( imageFullName(PSF) ) ) {
     296          19 :         if ( doesImageExist( imageFullName(SUMWT)) ) {
     297          18 :           std::shared_ptr<ImageInterface<Float> > imptr;
     298          18 :           buildImage(imptr, imageFullName(SUMWT) );
     299          18 :           itsNFacets = imptr->shape()[0];
     300          18 :           itsFacetId = 0;
     301          18 :           itsUseWeight = getUseWeightImage( *imptr );
     302          18 :           itsPBScaleFactor = 1.0; // No need to set properly here
     303             :                                   // as it will be calc'd in ()
     304             :           // Redo this here as psf may have different coordinates
     305          18 :           itsCoordSys = imptr->coordinates();
     306          18 :           itsMiscInfo =imptr->miscInfo();
     307          36 :           if ( itsUseWeight 
     308          18 :                and not doesImageExist( imageFullName(WEIGHT) ) ) {
     309           0 :             throw AipsError(
     310             :               "Internal error : Sumwt has a useweightimage=True"
     311             :               " but the weight image does not exist."
     312           0 :             );
     313             :           }
     314          18 :         } else {
     315           1 :           if (not noRequireSumwt) { // .sumwt image required?
     316             :               // -> probably not for just the minor cycle (aka task deconvolve)
     317           0 :               throw AipsError(
     318             :                 "SumWt information does not exist."
     319             :                 " Please create either a PSF or Residual"
     320           0 :               );
     321             :           } else {
     322             :             os << "SumWt does not exist. Proceeding only with PSF"
     323           1 :               << LogIO::POST;
     324           1 :             std::shared_ptr<ImageInterface<Float> > imptr;
     325           1 :             if ( doesImageExist( imageFullName(RESIDUAL) ) ) {
     326           1 :               buildImage(imptr, imageFullName(RESIDUAL) );
     327             :             }
     328             :             else {
     329           0 :               buildImage(imptr, imageFullName(PSF) );
     330             :             }
     331             : 
     332           1 :             itsNFacets = 1;
     333           1 :             itsFacetId = 0;
     334           1 :             itsUseWeight = False;
     335           1 :             itsPBScaleFactor = 1.0;
     336           1 :             itsCoordSys = imptr->coordinates();
     337           1 :             itsMiscInfo = imptr->miscInfo();
     338           1 :           }
     339             :         }
     340             :       } // if psf or residual exist
     341             :     } // Handle special case
     342             : 
     343          19 :     if (ignorefacets == True) itsNFacets = 1;
     344             : 
     345             :     // Why again ?
     346          19 :     init();
     347             : 
     348          19 :     validate();
     349          19 :   }
     350             : 
     351             :   // used from getSubImageStore(), for example when creating the facets list
     352             :   // this would be safer if it was refactored as a copy constructor of the generic stuff +
     353             :   // initialization of the facet related parameters
     354           0 :   SIImageStore::SIImageStore(const std::shared_ptr<ImageInterface<Float> > &modelim,
     355             :                              const std::shared_ptr<ImageInterface<Float> > &residim,
     356             :                              const std::shared_ptr<ImageInterface<Float> > &psfim,
     357             :                              const std::shared_ptr<ImageInterface<Float> > &weightim,
     358             :                              const std::shared_ptr<ImageInterface<Float> > &restoredim,
     359             :                              const std::shared_ptr<ImageInterface<Float> > &maskim,
     360             :                              const std::shared_ptr<ImageInterface<Float> > &sumwtim,
     361             :                              const std::shared_ptr<ImageInterface<Float> > &gridwtim,
     362             :                              const std::shared_ptr<ImageInterface<Float> > &pbim,
     363             :                              const std::shared_ptr<ImageInterface<Float> > &restoredpbcorim,
     364             :                              const std::shared_ptr<ImageInterface<Float> > & tempworkimage,
     365             :                              const CoordinateSystem &csys,
     366             :                              const IPosition &imshape,
     367             :                              const String &imagename,
     368             :                              const String &objectname,
     369             :                              const Record &miscinfo,
     370             :                              const Int facet, const Int nfacets,
     371             :                              const Int chan, const Int nchanchunks,
     372             :                              const Int pol, const Int npolchunks,
     373           0 :                              const Bool useweightimage)
     374             :   {
     375             :       
     376             : 
     377           0 :     itsPsf=psfim;
     378           0 :     itsModel=modelim;
     379           0 :     itsResidual=residim;
     380             :     /* if(residim){
     381             :      LatticeLocker lock1(*itsResidual, FileLocker::Read);
     382             :      cerr << "RESIDMAX " << max(itsResidual->get()) <<  "   " << max(residim->get()) << endl;
     383             :      }*/
     384           0 :     itsWeight=weightim;
     385           0 :     itsImage=restoredim;
     386           0 :     itsMask=maskim;
     387             : 
     388           0 :     itsSumWt=sumwtim;
     389             : 
     390           0 :     itsGridWt=gridwtim;
     391           0 :     itsPB=pbim;
     392           0 :     itsImagePBcor=restoredpbcorim;
     393           0 :     itsTempWorkIm=tempworkimage;
     394             : 
     395           0 :     itsPBScaleFactor=1.0;// No need to set properly here as it will be computed in makePSF.
     396             : 
     397           0 :     itsObjectName = objectname;
     398           0 :     itsMiscInfo = miscinfo;
     399             : 
     400           0 :     itsNFacets = nfacets;
     401           0 :     itsFacetId = facet;
     402           0 :     itsNChanChunks = nchanchunks;
     403           0 :     itsChanId = chan;
     404           0 :     itsNPolChunks = npolchunks;
     405           0 :     itsPolId = pol;
     406             : 
     407           0 :     itsOverWrite=False;
     408           0 :     itsUseWeight=useweightimage;
     409             : 
     410           0 :     itsParentImageShape = imshape; 
     411           0 :     itsImageShape = imshape;
     412             : 
     413           0 :     itsParentCoordSys = csys;
     414           0 :     itsCoordSys = csys; // Hopefully this doesn't change for a reference image
     415           0 :     itsImageName = imagename;
     416             : 
     417           0 :     itsIsSingleDishStore = False;
     418             : 
     419             :     //-----------------------
     420           0 :     init(); // Connect parent pointers to the images.
     421             :     //-----------------------
     422             : 
     423             :     // Set these to null, to be set later upon first access.
     424           0 :     itsPsf.reset( );
     425           0 :     itsModel.reset( );
     426           0 :     itsResidual.reset( );
     427           0 :     itsWeight.reset( );
     428           0 :     itsImage.reset( );
     429           0 :     itsMask.reset( );
     430           0 :     itsSumWt.reset( );
     431           0 :     itsPB.reset( );
     432             : 
     433           0 :     validate();
     434           0 :   }
     435             :   
     436          60 :    void SIImageStore::validate()
     437             :   {
     438             :     // There are two valid states. Check for at least one of them. 
     439          60 :     Bool inValidState = False;
     440             :     
     441          60 :     stringstream oss;
     442             :     { // Initialize error message
     443             :       oss
     444          60 :         << "shape:" << itsImageShape
     445          60 :           << " parentimageshape:" << itsParentImageShape
     446          60 :         << " nfacets:" << itsNFacets << "x" << itsNFacets 
     447          60 :           << " facetid:" << itsFacetId 
     448          60 :         << " nchanchunks:" << itsNChanChunks << " chanid:" << itsChanId 
     449          60 :         << " npolchunks:" << itsNPolChunks << " polid:" << itsPolId 
     450          60 :         << " coord-dim:" << itsCoordSys.nPixelAxes() 
     451          60 :         << " psf/res:" << (hasPsf() or hasResidual());
     452          60 :       if ( hasSumWt() ) oss << " sumwtshape : " << sumwt()->shape();
     453          60 :       oss << endl;
     454             :     }
     455             : 
     456             :     try {
     457             : 
     458          60 :       if ( itsCoordSys.nPixelAxes() != 4 ) inValidState = False;
     459             : 
     460             :       // (1) Regular imagestore
     461          60 :       if ( 
     462          60 :               itsNFacets == 1     and itsFacetId == 0
     463          60 :           and itsNChanChunks == 1 and itsChanId == 0
     464          60 :           and itsNPolChunks == 1  and itsPolId == 0 ) {
     465          60 :         Bool sumWtShapeOK = hasSumWt() and sumwt()->shape()[0] == 1;
     466          60 :         if ( itsImageShape.isEqual(itsParentImageShape)
     467          60 :              and ( sumWtShapeOK or not hasSumWt() )
     468         120 :              and itsParentImageShape.product() > 0 ) inValidState = True;
     469          60 :       }
     470             :       // (2) Reference Sub Imagestore
     471           0 :       else if ( 
     472           0 :              ( itsNFacets > 1     and itsFacetId >= 0 )
     473           0 :           or ( itsNChanChunks > 1 and itsChanId >= 0 )
     474           0 :           or ( itsNPolChunks > 1  and itsPolId >= 0 ) ) {
     475             :         // If shape is still unset, even when the first image has been made....
     476             :         Bool imgShapeOK1 =
     477           0 :           ( itsImageShape.product() > 0 and ( hasPsf() or hasResidual() ) );
     478             :         Bool imgShapeOK2 =
     479           0 :           ( itsImageShape.isEqual(IPosition(4,0,0,0,0)) and
     480           0 :             ( not hasPsf() and not hasResidual() )
     481           0 :           );
     482           0 :         Bool imgShapeOK = imgShapeOK1 or imgShapeOK2;
     483             :         Bool sumWtShapeOK =
     484           0 :           hasSumWt() and sumwt()->shape()[0] == 1; // One facet only.
     485             : 
     486           0 :         if (  imgShapeOK and ( itsParentImageShape.product() > 0 )
     487           0 :               and ( itsFacetId < itsNFacets*itsNFacets )
     488             :               // and (itsChanId<=itsNChanChunks) // chanchunks can be larger...
     489           0 :               and ( itsPolId < itsNPolChunks )
     490           0 :               and ( sumWtShapeOK or not hasSumWt() ) ) inValidState = True;
     491             :       }
     492             : 
     493             :     }
     494           0 :     catch ( AipsError &err ) {
     495           0 :       inValidState = False;
     496           0 :       oss << "  |||||  " << err.getMesg() << endl;
     497           0 :     }
     498             : 
     499          60 :     if ( not inValidState ) {
     500           0 :       throw AipsError(
     501           0 :         "Internal Error : Invalid ImageStore state : " + oss.str()
     502           0 :       );
     503             :     }
     504             : 
     505          60 :   }
     506             : 
     507             : 
     508             :   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     509             : 
     510           0 :   std::shared_ptr<SIImageStore> SIImageStore::getSubImageStore(const Int facet, const Int nfacets, 
     511             :                                                           const Int chan, const Int nchanchunks, 
     512             :                                                           const Int pol, const Int npolchunks)
     513             :   {
     514             :    
     515           0 :     return std::make_shared<SIImageStore>(itsModel, itsResidual, itsPsf, itsWeight, itsImage, itsMask, itsSumWt, itsGridWt, itsPB, itsImagePBcor, itsTempWorkIm, itsCoordSys, itsImageShape, itsImageName, itsObjectName, itsMiscInfo, facet, nfacets, chan, nchanchunks, pol, npolchunks, itsUseWeight);
     516             :   }
     517             : 
     518             :   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     519             :   //// Either read an image from disk, or construct one. 
     520             : 
     521         315 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::openImage(const String imagenamefull, 
     522             :                                                              const Bool overwrite, 
     523             :                                                              const Bool dosumwt, const Int nfacetsperside, const Bool checkCoordSys)
     524             :   {
     525             : 
     526             : 
     527         315 :     std::shared_ptr<ImageInterface<Float> > imPtr;
     528         315 :     IPosition useShape( itsParentImageShape );
     529             : 
     530         315 :     if( dosumwt ) // change shape to sumwt image shape.
     531             :       {
     532          37 :         useShape[0] = nfacetsperside;
     533          37 :         useShape[1] = nfacetsperside;
     534             :         //      cout << "openImage : Making sumwt grid : using shape : " << useShape << endl;
     535             :       }
     536             : 
     537             :     //    overwrite=False; /// HARD CODING THIS. See CAS-6937.
     538             : 
     539             :     //    cout << "Open image : " << imagenamefull << "    useShape : " << useShape << endl;
     540             : 
     541             :     // if image exists
     542             :     //      if overwrite=T
     543             :     //           try to make new image
     544             :     //           if not, try to open existing image
     545             :     //                     if cannot, complain.
     546             :     //       if overwrite=F
     547             :     //           try to open existing image
     548             :     //           if cannot, complain
     549             :     // if image does not exist
     550             :     //       try to make new image
     551             :     //       if cannot, complain
     552         315 :     Bool dbg=False;
     553         315 :     if( doesImageExist( imagenamefull ) )
     554             :       {
     555             :         ///// not used since itsOverWrite is hardcoded to FALSE (CAS-6937)
     556         232 :         if (overwrite) //overwrite and make new image
     557             :           {
     558           0 :             if(dbg) cout << "Trying to overwrite and open new image named : " << imagenamefull << " ow:"<< overwrite << endl;
     559             :             try{
     560           0 :               buildImage(imPtr, useShape, itsParentCoordSys, imagenamefull) ;
     561           0 :               LatticeLocker lock1(*imPtr, FileLocker::Write);
     562             :               // initialize to zeros...
     563           0 :               imPtr->set(0.0);
     564           0 :             }
     565           0 :             catch (AipsError &x){
     566           0 :               if(dbg)cout << "Cannot overwrite : " << x.getMesg() << endl;
     567           0 :               if(dbg)cout << "Open already ? : " << Table::isOpened( imagenamefull ) << "  Writable ? : " << Table::isWritable( imagenamefull ) << endl;
     568           0 :             if(Table::isWritable( imagenamefull ))
     569             :               {
     570           0 :                 if(dbg) cout << "--- Trying to open existing image : "<< imagenamefull << endl;
     571             :                 try{
     572           0 :                   buildImage( imPtr, imagenamefull );
     573             :                 }
     574           0 :                 catch (AipsError &x){
     575           0 :                   throw( AipsError("Writable table exists, but cannot open : " + x.getMesg() ) );
     576           0 :                 }
     577             :               }// is table writable
     578             :             else
     579             :               {
     580           0 :                 throw( AipsError("Cannot overwrite existing image. : " + x.getMesg() ) );
     581             :               }
     582           0 :             }
     583             :           }// overwrite existing image
     584             :         else // open existing image ( Always tries this )
     585             :           {
     586             :             if(1) //Table::isWritable( imagenamefull ))
     587             :               {
     588         232 :                 if(dbg) cout << "Trying to open existing image : "<< imagenamefull << endl;
     589             :                 try{
     590         232 :                   buildImage( imPtr, imagenamefull ) ;
     591             : 
     592         232 :                   if( !dosumwt)
     593             :                     {
     594             :                       //cout << useShape << "  and " << imPtr->shape() << " ---- " << useShape.product() << " : " << itsCoordSys.nCoordinates() << endl;
     595             :                       // Check if coordsys and shape of this image are consistent with current ones (if filled)
     596             : 
     597         211 :                       if( useShape.product()>0 &&  ! useShape.isEqual( imPtr->shape() ) )
     598             :                         {
     599           0 :                           ostringstream oo1,oo2;
     600           0 :                           oo1 << useShape; oo2 << imPtr->shape();
     601           0 :                           throw( AipsError( "There is a shape mismatch between existing images ("+oo2.str()+") and current parameters ("+oo1.str()+"). If you are attempting to restart a run with a new image shape, please change imagename and supply the old model or mask as inputs (via the startmodel or mask parameters) so that they can be regridded to the new shape before continuing." ) );
     602           0 :                         }
     603             : 
     604             :                       
     605             :                      
     606         211 :                       if( itsParentCoordSys.nCoordinates()>0 &&  checkCoordSys && ! itsParentCoordSys.near( imPtr->coordinates()) )
     607             :                         {
     608             :                           /// Implement an exception to get CAS-9977 to work. Modify the current coordsys to match the parent.
     609             :                           /// "The DirectionCoordinates have differing latpoles"
     610           0 :                           if( itsParentCoordSys.errorMessage().contains("differing latpoles") )
     611             :                             {
     612           0 :                               DirectionCoordinate dcord = itsParentCoordSys.directionCoordinate();
     613             :                               //cout << "Latpole from parent : " << dcord.longLatPoles() << endl;
     614             :                               
     615           0 :                               DirectionCoordinate dcord2 = imPtr->coordinates().directionCoordinate();
     616             :                               //cout << "Latpole from imPtr : " << dcord2.longLatPoles() << endl;
     617             :                       
     618           0 :                             LogIO os( LogOrigin("SIImageStore","Open existing Images",WHERE) );
     619           0 :                             os  << " Mismatch in Csys latpoles between existing image on disk (" << dcord2.longLatPoles() <<  ") and current imaging run (" << dcord.longLatPoles() << ") : " << itsParentCoordSys.errorMessage() << " -- Resetting to match image on disk" << LogIO::WARN << LogIO::POST;
     620             :                             //                       cout << "Set the coordinate from the Parent value" << endl;
     621             :                             //imPtr->setCoordinateInfo( itsParentCoordSys );
     622           0 :                             itsParentCoordSys = imPtr->coordinates();
     623           0 :                             }
     624             :                           
     625             :                           // Check again. 
     626           0 :                           if ( ! itsParentCoordSys.near( imPtr->coordinates() ) )
     627             :                             {
     628             :                               //cout << " Still different..." << endl;
     629           0 :                               throw( AipsError( "There is a coordinate system mismatch between existing images on disk and current parameters ("+itsParentCoordSys.errorMessage()+"). If you are attempting to restart a run, please change imagename and supply the old model or mask as inputs (via the startmodel or mask parameters) so that they can be regridded to the new coordinate system before continuing. " ) );
     630             :                             }
     631             :                               //}
     632             :                         }
     633             :                     }// not dosumwt
     634             :                 }
     635           0 :                 catch (AipsError &x){
     636           0 :                   throw( AipsError("Cannot open existing image : "+imagenamefull+" : " + x.getMesg() ) );
     637           0 :                 }
     638             :               }// is table writable
     639             :             else // table exists but not writeable
     640             :               {
     641             :                 if(dbg)cout << "Table exists but not writeable : " << imagenamefull << "  --- Open : " << Table::isOpened( imagenamefull ) << endl;
     642             :                 throw( AipsError("Image exists but not able to open for writes :"+imagenamefull+ ". Opened elsewhere : " + String::toString(Table::isOpened(imagenamefull))) );
     643             :               }
     644             :           }// open existing image
     645             :       }// if image exists
     646             :       else // image doesn't exist. make new one
     647             :         {
     648          83 :           if(dbg) cout << "Trying to open new image named : " << imagenamefull <<  endl;
     649             :           try{
     650          83 :             buildImage(imPtr, useShape, itsParentCoordSys, imagenamefull) ;
     651             :             // initialize to zeros...
     652             :             {
     653          83 :             LatticeLocker lock1(*imPtr, FileLocker::Write);
     654          83 :             imPtr->set(0.0);
     655          83 :             imPtr->flush();
     656          83 :             imPtr->unlock();
     657          83 :             }
     658             :           }
     659           0 :           catch (AipsError &x){
     660           0 :             throw( AipsError("Cannot make new image. : " + x.getMesg() ) );
     661           0 :           }
     662             :         }
     663             : 
     664             : 
     665             :       //////////////////////////////////////
     666             :     /*      
     667             :     if( overwrite || !Table::isWritable( imagenamefull ) )
     668             :       {
     669             :         cout << "Trying to open new image named : " << imagenamefull << " ow:"<< overwrite << endl;
     670             :         imPtr.reset( new PagedImage<Float> (useShape, itsCoordSys, imagenamefull) );
     671             :         // initialize to zeros...
     672             :         imPtr->set(0.0);
     673             :       }
     674             :     else
     675             :       {
     676             :         if(Table::isWritable( imagenamefull ))
     677             :           {
     678             :             cout << "Trying to open existing image : "<< imagenamefull << endl;
     679             :             try{
     680             :               imPtr.reset( new PagedImage<Float>( imagenamefull ) );
     681             :             }
     682             :             catch (AipsError &x){
     683             :               cerr << "Writable table exists, but cannot open. Creating temp image. : " << x.getMesg() << endl;
     684             :               imPtr.reset( new TempImage<Float> (useShape, itsCoordSys) );
     685             :               //  imPtr=new PagedImage<Float> (useShape, itsCoordSys, imagenamefull);
     686             :               imPtr->set(0.0);
     687             :             }
     688             :           }
     689             :         else
     690             :           {
     691             :             cerr << "Table " << imagenamefull << " is not writeable. Creating temp image." << endl;
     692             :             imPtr.reset( new TempImage<Float> (useShape, itsCoordSys) );
     693             :             imPtr->set(0.0);
     694             :           }
     695             :       }
     696             :     */
     697         630 :     return imPtr;
     698         315 :   }
     699             : 
     700          83 :   void SIImageStore::buildImage(std::shared_ptr<ImageInterface<Float> > &imptr, IPosition shape,
     701             :                                 CoordinateSystem csys, const String name)
     702             :   {
     703         166 :     LogIO os( LogOrigin("SIImageStore", "Open non-existing image", WHERE) );
     704          83 :     os  <<"Opening image, name: " << name << LogIO::DEBUG1;
     705             : 
     706          83 :     itsOpened++;
     707             :     //For some reason cannot open a new paged image with UserNoread directly
     708             :     {
     709          83 :       PagedImage<Float> godot(shape, csys, name);
     710          83 :       godot.unlock();
     711          83 :     }
     712          83 :     TableLock::LockOption locktype=TableLock::AutoNoReadLocking;
     713             :     //TableLock::LockOption locktype=TableLock::UserLocking;
     714             :     /*if((name.contains(imageExts(PSF)) && !name.contains(imageExts(PSF)+".tt"))|| (name.contains(imageExts(RESIDUAL))&& !name.contains(imageExts(RESIDUAL)+".tt")) || (name.contains(imageExts(SUMWT)) && !name.contains(imageExts(SUMWT)+".tt"))){
     715             :       locktype=TableLock::UserNoReadLocking;
     716             :       }*/
     717          83 :     imptr.reset( new PagedImage<Float> (name, locktype) );
     718             :     {
     719          83 :       LatticeLocker lock1(*imptr, FileLocker::Write);
     720          83 :       initMetaInfo(imptr, name);
     721          83 :       imptr->unlock();
     722          83 :     }
     723             :     /*
     724             :     Int MEMFACTOR = 18;
     725             :     Double memoryMB=HostInfo::memoryTotal(True)/1024/(MEMFACTOR*itsOpened);
     726             : 
     727             : 
     728             :     TempImage<Float> *tptr = new TempImage( TiledShape(shape, tileShape()), csys, memoryBeforeLattice() ) ;
     729             : 
     730             :     tptr->setMaximumCacheSize(shape.product());
     731             :     tptr->cleanCache();
     732             : 
     733             :     imptr.reset( tptr );
     734             :     
     735             :     */
     736          83 :   }
     737             : 
     738         280 :   void SIImageStore::buildImage(std::shared_ptr<ImageInterface<Float> > &imptr, const String name)
     739             :   {
     740         560 :     LogIO os(LogOrigin("SIImageStore", "Open existing Images", WHERE));
     741         280 :     os  <<"Opening image, name: " << name << LogIO::DEBUG1;
     742             : 
     743         280 :     itsOpened++;
     744         280 :     if ( Table::isReadable(name) ) {
     745         280 :       TableLock::LockOption locktype=TableLock::AutoNoReadLocking;
     746             :       /*  if (
     747             :             (  name.contains(imageExts(PSF)) and
     748             :                not name.contains(imageExts(PSF) + ".tt")
     749             :             ) or
     750             :             (  name.contains(imageExts(RESIDUAL)) and
     751             :                not name.contains(imageExts(RESIDUAL)+".tt")
     752             :             ) or
     753             :             (  name.contains(imageExts(SUMWT)) and 
     754             :                not name.contains(imageExts(SUMWT)+".tt")
     755             :             )
     756             :           ) {
     757             :             locktype=TableLock::UserNoReadLocking;
     758             :           }
     759             :       */
     760         280 :       Table table(name, locktype);
     761         280 :       String type = table.tableInfo().type();
     762         280 :       if ( type != TableInfo::type(TableInfo::PAGEDIMAGE) ) {
     763             : 
     764           0 :         imptr.reset( new PagedImage<Float>( table ) );
     765           0 :         imptr->unlock();
     766           0 :         return;
     767             :       }
     768         280 :     }
     769             : 
     770         280 :     LatticeBase* latt =ImageOpener::openImage(name);
     771         280 :     if (not latt) {
     772           0 :       throw AipsError("Error in opening Image : "+name);
     773             :     }
     774         280 :     DataType dtype = latt->dataType();
     775         280 :     if (dtype == TpFloat) {
     776         280 :       imptr.reset(dynamic_cast<ImageInterface<Float>* >(latt));
     777             :     } else {
     778           0 :       throw AipsError( "Need image to have float values :  "+name);
     779             :     }
     780             : 
     781             :     /*
     782             :     std::shared_ptr<casacore::ImageInterface<Float> > fim;
     783             :     std::shared_ptr<casacore::ImageInterface<Complex> > cim;
     784             : 
     785             :     std::tie(fim , cim)=ImageFactory::fromFile(name);
     786             :     if (fim) {
     787             :       imptr.reset(
     788             :         dynamic_cast<std::shared_ptr<casacore::ImageInterface<Float> > >(*fim)
     789             :       );
     790             :     } else {
     791             :       throw AipsError("Cannot open with ImageFactory : "+name);
     792             :     }
     793             :     */
     794             : 
     795             :     /*
     796             :     IPosition cimageShape;
     797             :     CoordinateSystem cimageCoord = StokesImageUtil::CStokesCoord(
     798             :       itsCoordSys,
     799             :       whichStokes,
     800             :       itsDataPolRep
     801             :     );
     802             :     */
     803             : 
     804         280 :   }
     805             : 
     806             :   /**
     807             :    * Sets ImageInfo and MiscInfo on an image
     808             :    *
     809             :    * @param imptr image to initialize
     810             :    */
     811          83 :   void SIImageStore::initMetaInfo(std::shared_ptr<ImageInterface<Float> > &imptr,
     812             :                                   const String name)
     813             :   {
     814             :       // Check objectname, as one of the mandatory fields. What this is meant to check is -
     815             :       // has the metainfo been initialized? If not, grab info from associated PSF
     816          83 :     LatticeLocker lock1(*imptr, FileLocker::Write);
     817          83 :       if (not itsObjectName.empty()) {
     818          83 :           ImageInfo info = imptr->imageInfo();
     819          83 :           info.setObjectName(itsObjectName);
     820          83 :           imptr->setImageInfo(info);
     821          83 :           imptr->setMiscInfo(itsMiscInfo);
     822          83 :       } else if (std::string::npos == name.find(imageExts(PSF))) {
     823           0 :           auto srcImg = psf(0);
     824           0 :           if (nullptr != srcImg) {
     825           0 :               imptr->setImageInfo(srcImg->imageInfo());
     826           0 :               imptr->setMiscInfo(srcImg->miscInfo());
     827             :           }
     828           0 :       }
     829          83 :       imptr->unlock();
     830          83 :   }
     831             : 
     832             : 
     833             :   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     834           0 :   void SIImageStore::setMiscInfo(const Record miscinfo)
     835             :   {
     836           0 :     itsMiscInfo = miscinfo;
     837           0 :   }
     838             : 
     839           0 :   void SIImageStore::setObjectName(const String name)
     840             :   {
     841           0 :     itsObjectName = name;
     842           0 :   }
     843             : 
     844             :   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     845             : 
     846         253 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::makeSubImage(const Int facet, const Int nfacets,
     847             :                                                                 const Int chan, const Int nchanchunks,
     848             :                                                                 const Int pol, const Int npolchunks,
     849             :                                                                 ImageInterface<Float>& image)
     850             :   {
     851             :     //assuming n x n facets
     852         253 :     Int nx_facets=Int(sqrt(Double(nfacets)));
     853         506 :     LogIO os( LogOrigin("SynthesisImager","makeFacet") );
     854             :      // Make the output image
     855         253 :     Slicer imageSlicer;
     856             : 
     857             :     // Add checks for all dimensions..
     858         253 :     if((facet>(nfacets-1))||(facet<0)) {
     859           0 :       os << LogIO::SEVERE << "Illegal facet " << facet << LogIO::POST;
     860           0 :       return std::shared_ptr<ImageInterface<Float> >();
     861             :     }
     862         253 :     IPosition imshp=image.shape();
     863         253 :     IPosition blc(imshp.nelements(), 0);
     864         253 :     IPosition trc=imshp-1;
     865         253 :     IPosition inc(imshp.nelements(), 1);
     866             : 
     867             :     /// Facets
     868         253 :     Int facetx = facet % nx_facets; 
     869         253 :     Int facety = (facet - facetx) / nx_facets;
     870         253 :     Int sizex = imshp(0) / nx_facets;
     871         253 :     Int sizey = imshp(1) / nx_facets;
     872         253 :     blc(1) = facety * sizey; 
     873         253 :     trc(1) = blc(1) + sizey - 1;
     874         253 :     blc(0) = facetx * sizex; 
     875         253 :     trc(0) = blc(0) + sizex - 1;
     876             : 
     877             :     /// Pol Chunks
     878         253 :     Int sizepol = imshp(2) / npolchunks;
     879         253 :     blc(2) = pol * sizepol;
     880         253 :     trc(2) = blc(2) + sizepol - 1;
     881             : 
     882             :     /// Chan Chunks
     883         253 :     Int sizechan = imshp(3) / nchanchunks;
     884         253 :     blc(3) = chan * sizechan;
     885         253 :     trc(3) = blc(3) + sizechan - 1;
     886             : 
     887         253 :     LCBox::verify(blc, trc, inc, imshp);
     888         253 :     Slicer imslice(blc, trc, inc, Slicer::endIsLast);
     889             : 
     890             :     // Now create the sub image
     891         253 :     std::shared_ptr<ImageInterface<Float> >  referenceImage( new SubImage<Float>(image, imslice, True) );
     892             :     {
     893         253 :       LatticeLocker lock1(*referenceImage, FileLocker::Write);
     894         253 :       referenceImage->setMiscInfo(image.miscInfo());
     895         253 :       referenceImage->setUnits(image.units());
     896             : 
     897         253 :     }
     898             : 
     899             :     // cout << "Made Ref subimage of shape : " << referenceImage->shape() << endl;
     900             : 
     901         253 :     return referenceImage;
     902             :     
     903         253 :   }
     904             : 
     905             : 
     906             : 
     907             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     908             : 
     909         109 :   SIImageStore::~SIImageStore() 
     910             :   {
     911         109 :   }
     912             : 
     913             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     914             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     915             : 
     916         114 :   Bool SIImageStore::releaseLocks() 
     917             :   {
     918             :     //LogIO os( LogOrigin("SIImageStore","releaseLocks",WHERE) );
     919             : 
     920             :     //    String fname( itsImageName+String(".info") );
     921             :     //    makePersistent( fname );
     922             : 
     923         114 :     if( itsPsf ) releaseImage( itsPsf );
     924         114 :     if( itsModel ) { releaseImage( itsModel ); }
     925         114 :     if( itsResidual ) releaseImage( itsResidual );
     926         114 :     if( itsImage ) releaseImage( itsImage );
     927         114 :     if( itsWeight ) releaseImage( itsWeight );
     928         114 :     if( itsMask ) releaseImage( itsMask );
     929         114 :     if( itsSumWt ) releaseImage( itsSumWt );
     930         114 :     if( itsGridWt ) releaseImage( itsGridWt );
     931         114 :     if( itsPB ) releaseImage( itsPB );
     932         114 :     if( itsImagePBcor ) releaseImage( itsImagePBcor );
     933             : 
     934         114 :     return True; // do something more intelligent here.
     935             :   }
     936             : 
     937           0 :   Bool SIImageStore::releaseComplexGrids() 
     938             :   {
     939             :     //LogIO os( LogOrigin("SIImageStore","releaseComplexGrids",WHERE) );
     940             : 
     941           0 :     if( itsForwardGrid ) releaseImage( itsForwardGrid );
     942           0 :     if( itsBackwardGrid ) releaseImage( itsBackwardGrid );
     943             : 
     944           0 :     return True; // do something more intelligent here.
     945             :   }
     946             : 
     947         261 :   void SIImageStore::releaseImage( std::shared_ptr<ImageInterface<Float> > &im )
     948             :   {
     949             :     //cerr << this << " releaseimage " << im.get() << endl;
     950             :     //LogIO os( LogOrigin("SIImageStore","releaseLocks",WHERE) );
     951         261 :     im->flush();
     952             :     //os << LogIO::WARN << "clear cache" << LogIO::POST;
     953         261 :     im->clearCache();
     954             :     //os << LogIO::WARN << "unlock" << LogIO::POST;
     955         261 :     im->unlock();
     956             :     //os << LogIO::WARN << "tempClose" << LogIO::POST;
     957             :     //im->tempClose();
     958             :     //os << LogIO::WARN << "NULL" << LogIO::POST;
     959         261 :     im.reset();  // This was added to allow modification by modules independently
     960         261 :   }
     961             :   
     962           0 :   void SIImageStore::releaseImage( std::shared_ptr<ImageInterface<Complex> > &im )
     963             :   {
     964           0 :     im->tempClose();
     965           0 :   }
     966             : 
     967             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     968             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
     969           0 :   Vector<String> SIImageStore::getModelImageName()
     970             :   {
     971           0 :     Vector<String> mods(1);
     972           0 :     mods[0]=itsImageName + imageExts(MODEL);
     973           0 :     return mods;
     974           0 :   }
     975             : 
     976           5 :   Long SIImageStore::estimateRAM(){
     977             :     //right now this is estimated at 2MB for the 2 complex lattices;
     978           5 :     return Long(2000);
     979             :   }
     980           0 :   void SIImageStore::setModelImage( const Vector<String> &modelnames)
     981             :   {
     982           0 :     LogIO os( LogOrigin("SIImageStore","setModelImage",WHERE) );
     983             : 
     984           0 :     if( modelnames.nelements() > 1 )
     985           0 :       {throw( AipsError("Multiple starting model images are currently not supported. Please merge them before supplying as input to startmodel"));
     986             :         /// If needed, THIS is the place to add code to support lists of model images... perhaps regrid separately and add them up or some such thing.
     987             :       }
     988             : 
     989           0 :     if( modelnames.nelements()==1 ) { setModelImageOne( modelnames[0] ); }
     990           0 :   }
     991             : 
     992             : 
     993             : 
     994           0 :   void SIImageStore::setModelImageOne( const String &modelname , Int nterm)
     995             :   {
     996           0 :     LogIO os( LogOrigin("SIImageStore","setModelImageOne",WHERE) );
     997             : 
     998           0 :     if(modelname==String("")) return;
     999             : 
    1000           0 :     Bool multiterm=False;
    1001           0 :     if(nterm>-1)multiterm=True;
    1002           0 :     if(nterm==-1)nterm=0;
    1003             : 
    1004           0 :     Directory immodel( modelname ); //  +String(".model") );
    1005           0 :     if( !immodel.exists() ) 
    1006             :       {
    1007           0 :         os << "Starting model image " << modelname <<  " does not exist. No initial prediction will be done" << ((multiterm)?String(" for term")+String::toString(nterm) :"") << LogIO::POST;
    1008           0 :         return;
    1009             :       }
    1010             : 
    1011             :     // master merge 2019.01.08 - leaving in the commnets for now but clean up after it is verified 
    1012             :     //SHARED_PTR<PagedImage<Float> > newmodel( new PagedImage<Float>( modelname ) ); //+String(".model") ) );
    1013             :     //SHARED_PTR<ImageInterface<Float> > newmodel;
    1014           0 :     std::shared_ptr<ImageInterface<Float> > newmodel;
    1015           0 :     buildImage(newmodel, modelname);
    1016             :     // in master
    1017             :     //std::shared_ptr<PagedImage<Float> > newmodel( new PagedImage<Float>( modelname ) ); //+String(".model") ) );
    1018             : 
    1019           0 :     Bool hasMask = newmodel->isMasked(); /// || newmodel->hasPixelMask() ;
    1020             :     
    1021           0 :     if( hasMask )
    1022             :       {
    1023             :         
    1024           0 :         os << "Input startmodel has an internal mask. Setting masked pixels to zero" << LogIO::POST;
    1025             :         
    1026             :         try {
    1027             : 
    1028             :           ////// Neat function to replace masked pixels, but it will do it in-place.
    1029             :           ////// We need to not modify the input model on disk, but apply the mask only OTF before
    1030             :           //////  regridding to the target image,.
    1031             :           //      ImageMaskedPixelReplacer<Float> impr( newmodel, 0, "" );
    1032             :           //      impr.replace("0", False, False );
    1033             : 
    1034             :           
    1035           0 :           TempImage<Float> maskmodel( newmodel->shape(), newmodel->coordinates() );
    1036           0 :           IPosition inshape = newmodel->shape();
    1037           0 :           for(Int pol=0; pol<inshape[2]; pol++)
    1038             :             {
    1039           0 :               for(Int chan=0; chan<inshape[3]; chan++)
    1040             :                 {
    1041           0 :                   IPosition pos(4,0,0,pol,chan);
    1042             :                   std::shared_ptr<ImageInterface<Float> > subim=makeSubImage(0,1, 
    1043           0 :                                                                         chan, inshape[3],
    1044           0 :                                                                         pol, inshape[2], 
    1045           0 :                                                                         (*newmodel) );
    1046             :                   
    1047             :                   std::shared_ptr<ImageInterface<Float> > submaskmodel=makeSubImage(0,1, 
    1048           0 :                                                                                chan, inshape[3],
    1049           0 :                                                                                pol, inshape[2], 
    1050           0 :                                                                                maskmodel );
    1051             :                   
    1052           0 :                   ArrayLattice<Bool> pixmask( subim->getMask() );
    1053           0 :                   LatticeExpr<Float> masked( (*subim) * iif(pixmask,1.0,0.0) );
    1054           0 :                   submaskmodel->copyData( masked );
    1055           0 :                 }
    1056             :             }
    1057             :           
    1058             :           
    1059             : 
    1060             :           // Check shapes, coordsys with those of other images.  If different, try to re-grid here.
    1061           0 :           if( (newmodel->shape() != model(nterm)->shape()) ||  (! itsCoordSys.near(newmodel->coordinates() )) )
    1062             :             {
    1063           0 :               os << "Regridding input model " << modelname << " to target coordinate system for " << itsImageName << ".model" << ((multiterm)?".tt"+String::toString(nterm) :"") << LogIO::POST;
    1064           0 :               regridToModelImage( maskmodel, nterm );
    1065             :             }
    1066             :           else
    1067             :             {
    1068           0 :               os << "Copying input model " << modelname << " to " << itsImageName << ".model" << ((multiterm)?".tt"+String::toString(nterm) :"")  << LogIO::POST;
    1069           0 :               model(nterm)->copyData( LatticeExpr<Float> (maskmodel) );
    1070             :             }
    1071             :           
    1072             :           
    1073           0 :         } catch (AipsError &x) {
    1074           0 :           throw(AipsError("Setting masked pixels to zero for input startmodel : "+ x.getMesg()));
    1075           0 :         }
    1076             :         
    1077             :       }// hasMask
    1078             :     else // nomask
    1079             :       {
    1080             :         
    1081             :         // Check shapes, coordsys with those of other images.  If different, try to re-grid here.
    1082           0 :         if( (newmodel->shape() != model(nterm)->shape()) ||  (! itsCoordSys.near(newmodel->coordinates() )) )
    1083             :           {
    1084           0 :             os << "Regridding input model " << modelname << " to target coordinate system for " << itsImageName << ".model" << ((multiterm)?".tt"+String::toString(nterm) :"") << LogIO::POST;
    1085           0 :             regridToModelImage( *newmodel, nterm );
    1086             :           }
    1087             :         else
    1088             :           {
    1089           0 :             os << "Copying input model " << modelname << " to " << itsImageName << ".model" << ((multiterm)?".tt"+String::toString(nterm) :"")  << LogIO::POST;
    1090           0 :             model(nterm)->copyData( LatticeExpr<Float> (*newmodel) );
    1091             :           }
    1092             :       }//nomask
    1093           0 :   }
    1094             : 
    1095             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
    1096             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
    1097             : 
    1098         146 :   IPosition SIImageStore::getShape()
    1099             :   {
    1100         146 :     return itsImageShape;
    1101             :   }
    1102             : 
    1103          51 :   String SIImageStore::getName()
    1104             :   {
    1105          51 :     return itsImageName;
    1106             :   }
    1107             : 
    1108         106 :   String SIImageStore::imageFullName(IMAGE_IDS imageId)
    1109             :   {
    1110         106 :     return itsImageName + imageExts(imageId);
    1111             :   }
    1112             : 
    1113         149 :   uInt SIImageStore::getNTaylorTerms(Bool /*dopsf*/)
    1114             :   {
    1115         149 :     return 1;
    1116             :   }
    1117             : 
    1118             :   /*
    1119             :   void SIImageStore::checkRef( std::shared_ptr<ImageInterface<Float> > ptr, const String label )
    1120             :   {
    1121             :     if( ! ptr && itsImageName==String("reference") ) 
    1122             :       {throw(AipsError("Internal Error : Attempt to access null subImageStore "+label + " by reference."));}
    1123             :   }
    1124             :   */
    1125             : 
    1126        1024 :   void SIImageStore::accessImage( std::shared_ptr<ImageInterface<Float> > &ptr, 
    1127             :                     std::shared_ptr<ImageInterface<Float> > &parentptr, 
    1128             :                     const String label )
    1129             :   {
    1130             :     // if ptr is not null, assume it's OK. Perhaps add more checks.
    1131             : 
    1132             :     //cerr << "ACCIM itsptr" << ptr.get() << " parent " << parentptr.get() << " label " << label << endl;
    1133             :     
    1134        1024 :     Bool sw=False;
    1135        1024 :     if( label.contains(imageExts(SUMWT)) ) sw=True;
    1136             :     
    1137        1024 :     if( !ptr )
    1138             :       {
    1139             :         //cout << itsNFacets << " " << itsNChanChunks << " " << itsNPolChunks << endl;
    1140         315 :         if( itsNFacets>1 || itsNChanChunks>1 || itsNPolChunks>1 )
    1141             :           {
    1142           0 :             if( ! parentptr ) 
    1143             :               {
    1144             :                 //cout << "Making parent : " << itsImageName+label << "    sw : " << sw << endl; 
    1145           0 :                 parentptr = openImage(itsImageName+label , itsOverWrite, sw, itsNFacets );  
    1146           0 :                 if( sw) {setUseWeightImage( *parentptr, itsUseWeight ); }
    1147             :               }
    1148             :             //      cout << "Making facet " << itsFacetId << " out of " << itsNFacets << endl;
    1149             :             //cout << "Making chunk " << itsChanId << " out of " << itsNChanChunks << endl;
    1150             :             //ptr = makeFacet( itsFacetId, itsNFacets*itsNFacets, *parentptr );
    1151           0 :             ptr = makeSubImage( itsFacetId, itsNFacets*itsNFacets, 
    1152             :                                 itsChanId, itsNChanChunks, 
    1153             :                                 itsPolId, itsNPolChunks, 
    1154           0 :                                 *parentptr );
    1155           0 :             if( ! sw )
    1156             :               {
    1157           0 :                 itsImageShape = ptr->shape(); // over and over again.... FIX.
    1158           0 :                 itsCoordSys = ptr->coordinates();
    1159           0 :                 itsMiscInfo = ptr->miscInfo();
    1160             :               }
    1161             : 
    1162             :             //cout << "accessImage : " << label << " : sumwt : " << sw << " : shape : " << itsImageShape << endl;
    1163             :     
    1164             :           }
    1165             :         else
    1166             :           { //no facets of chanchunks
    1167         315 :             if(!parentptr){
    1168             :             ///coordsys for psf can be different ...shape should be the same.
    1169         313 :               ptr = openImage(itsImageName+label , itsOverWrite, sw, 1, !(label.contains(imageExts(PSF)))); }
    1170             :             else{
    1171           2 :               ptr=parentptr;
    1172             :             }
    1173             :             //cout << "Opening image : " << itsImageName+label << " of shape " << ptr->shape() << endl;
    1174             :           }
    1175             :       }
    1176             : 
    1177             :     //cerr << "ACCIM2 ptr " << ptr.get() << " lock " << itsReadLock.get() << endl;
    1178             :     //itsReadLock.reset(new LatticeLocker(*ptr, FileLocker::Read));
    1179             :     
    1180             :     //    DirectionCoordinate dcord = ptr->coordinates().directionCoordinate();
    1181             :     //    cout << "Latpole from " << label << " : " << dcord.longLatPoles() << endl;
    1182             : 
    1183        1024 :   }
    1184             : 
    1185             : 
    1186         108 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::psf(uInt /*nterm*/)
    1187             :   {
    1188         108 :     accessImage( itsPsf, itsParentPsf, imageExts(PSF) );
    1189             :     
    1190         108 :     return itsPsf;
    1191             :   }
    1192         208 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::residual(uInt /*nterm*/)
    1193             :   {
    1194         208 :     accessImage( itsResidual, itsParentResidual, imageExts(RESIDUAL) );
    1195             :     //    Record mi = itsResidual->miscInfo(); ostringstream oss;mi.print(oss);cout<<"MiscInfo(res) : " << oss.str() << endl;
    1196         208 :     return itsResidual;
    1197             :   }
    1198          67 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::weight(uInt /*nterm*/)
    1199             :   {
    1200          67 :     accessImage( itsWeight, itsParentWeight, imageExts(WEIGHT) );
    1201          67 :     return itsWeight;
    1202             :   }
    1203             : 
    1204         115 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::sumwt(uInt /*nterm*/)
    1205             :   {
    1206             : 
    1207         115 :     accessImage( itsSumWt, itsParentSumWt, imageExts(SUMWT) );
    1208             :     
    1209         115 :     if( itsNFacets>1 || itsNChanChunks>1 || itsNPolChunks>1 ) 
    1210           0 :       { itsUseWeight = getUseWeightImage( *itsParentSumWt );}
    1211         115 :     setUseWeightImage( *itsSumWt , itsUseWeight); // Sets a flag in the SumWt image. 
    1212             :     
    1213         115 :     return itsSumWt;
    1214             :   }
    1215             : 
    1216          37 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::model(uInt /*nterm*/)
    1217             :   {
    1218          37 :     accessImage( itsModel, itsParentModel, imageExts(MODEL) );
    1219          37 :     LatticeLocker lock1(*itsModel, FileLocker::Write);
    1220             :     // Set up header info the first time. 
    1221          37 :     itsModel->setUnits("Jy/pixel");
    1222             : 
    1223          74 :     return itsModel;
    1224          37 :   }
    1225          29 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::image(uInt /*nterm*/)
    1226             :   {
    1227          29 :     accessImage( itsImage, itsParentImage, imageExts(IMAGE) );
    1228          29 :     LatticeLocker lock1(*itsImage, FileLocker::Write);
    1229          29 :     itsImage->setUnits(Unit("Jy/beam"));
    1230          58 :     return itsImage;
    1231          29 :   }
    1232             : 
    1233         117 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::mask(uInt /*nterm*/)
    1234             :   {
    1235         117 :     accessImage( itsMask, itsParentMask, imageExts(MASK) );
    1236         117 :     return itsMask;
    1237             :   }
    1238           0 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::gridwt(IPosition newshape)
    1239             : 
    1240             :   {
    1241           0 :     if(newshape.empty()){
    1242           0 :       accessImage( itsGridWt, itsParentGridWt, imageExts(GRIDWT) );
    1243             :     }
    1244             :     else{
    1245           0 :       if(!itsGridWt  || (itsGridWt && (itsGridWt->shape() != newshape))){
    1246           0 :         itsGridWt.reset();  // deassign previous one hopefully it'll close it
    1247           0 :         CoordinateSystem newcoordsys=itsCoordSys;
    1248           0 :         if(newshape.nelements() > 4){
    1249           0 :           Matrix<Double> pc(1,1);      pc = 1.0;
    1250           0 :           LinearCoordinate zc(Vector<String>(1, "FIELD_ORDER"), Vector<String>(1, ""), Vector<Double>(1, 0.0), Vector<Double>(1,1.0), pc, Vector<Double>(1,0.0));
    1251           0 :           newcoordsys.addCoordinate(zc);
    1252           0 :         }
    1253           0 :           itsGridWt.reset(new PagedImage<Float>(newshape, newcoordsys, itsImageName+ imageExts(GRIDWT)));
    1254           0 :           initMetaInfo(itsGridWt, itsImageName+ imageExts(GRIDWT));
    1255             : 
    1256           0 :       }
    1257             :     }
    1258             :     /// change the coordinate system here, to uv.
    1259           0 :     return itsGridWt;
    1260             :   }
    1261             : 
    1262           0 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::tempworkimage(uInt /*term*/){
    1263           0 :     if(itsTempWorkIm) return itsTempWorkIm;
    1264           0 :     itsTempWorkIm.reset(new PagedImage<Float>(itsImageShape, itsCoordSys, itsImageName+ ".work.temp"));
    1265           0 :     static_cast<PagedImage<Float>* > (itsTempWorkIm.get())->set(0.0);
    1266           0 :     itsTempWorkIm->flush();
    1267           0 :     static_cast<PagedImage<Float>* > (itsTempWorkIm.get())->table().markForDelete();
    1268           0 :     return itsTempWorkIm;
    1269             :   }
    1270             :   
    1271         112 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::pb(uInt /*nterm*/)
    1272             :   {
    1273         112 :     accessImage( itsPB, itsParentPB, imageExts(PB) );
    1274         112 :     return itsPB;
    1275             :   }
    1276           0 :   std::shared_ptr<ImageInterface<Float> > SIImageStore::imagepbcor(uInt /*nterm*/)
    1277             :   {
    1278           0 :     accessImage( itsImagePBcor, itsParentImagePBcor, imageExts(IMAGEPBCOR) );
    1279           0 :     LatticeLocker lock1(*itsImagePBcor, FileLocker::Write);
    1280           0 :     itsImagePBcor->setUnits(Unit("Jy/beam"));
    1281           0 :     return itsImagePBcor;
    1282           0 :   }
    1283             : 
    1284           0 :   std::shared_ptr<ImageInterface<Complex> > SIImageStore::forwardGrid(uInt /*nterm*/){
    1285           0 :     if( itsForwardGrid ) // && (itsForwardGrid->shape() == itsImageShape))
    1286             :       {
    1287             :         //      cout << "Forward grid has shape : " << itsForwardGrid->shape() << endl;
    1288           0 :         return itsForwardGrid;
    1289             :       }
    1290           0 :     Vector<Int> whichStokes(0);
    1291           0 :     IPosition cimageShape;
    1292           0 :     cimageShape=itsImageShape;
    1293           0 :     MFrequency::Types freqframe = itsCoordSys.spectralCoordinate(itsCoordSys.findCoordinate(Coordinate::SPECTRAL)).frequencySystem(True);
    1294             :     // No need to set a conversion layer if image is in LSRK already or it is 'Undefined'
    1295           0 :     if(freqframe != MFrequency::LSRK && freqframe!=MFrequency::Undefined && freqframe!=MFrequency::REST) 
    1296           0 :       { itsCoordSys.setSpectralConversion("LSRK"); }
    1297           0 :     CoordinateSystem cimageCoord = StokesImageUtil::CStokesCoord( itsCoordSys,
    1298           0 :                                                                   whichStokes, itsDataPolRep);
    1299           0 :     cimageCoord.setObsInfo(itsCoordSys.obsInfo());
    1300           0 :     cimageShape(2)=whichStokes.nelements();      
    1301             :     //cout << "Making forward grid of shape : " << cimageShape << " for imshape : " << itsImageShape << endl;
    1302           0 :     itsForwardGrid.reset( new TempImage<Complex>(TiledShape(cimageShape, tileShape()), cimageCoord, memoryBeforeLattice()) );
    1303             :     //if(image())
    1304           0 :     if(hasRestored()){
    1305           0 :       LatticeLocker lock1(*itsForwardGrid, FileLocker::Write);
    1306           0 :       itsForwardGrid->setImageInfo((image())->imageInfo());
    1307             : 
    1308           0 :     }
    1309           0 :     return itsForwardGrid;
    1310           0 :   }
    1311             : 
    1312          14 :   std::shared_ptr<ImageInterface<Complex> > SIImageStore::backwardGrid(uInt /*nterm*/){
    1313          14 :     if( itsBackwardGrid ) //&& (itsBackwardGrid->shape() == itsImageShape))
    1314             :       {
    1315             :         //      cout << "Backward grid has shape : " << itsBackwardGrid->shape() << endl;
    1316           7 :         return itsBackwardGrid;
    1317             :       }
    1318           7 :     Vector<Int> whichStokes(0);
    1319           7 :     IPosition cimageShape;
    1320           7 :     cimageShape=itsImageShape;
    1321           7 :     MFrequency::Types freqframe = itsCoordSys.spectralCoordinate(itsCoordSys.findCoordinate(Coordinate::SPECTRAL)).frequencySystem(True);
    1322             :     // No need to set a conversion layer if image is in LSRK already or it is 'Undefined'
    1323           7 :     if(freqframe != MFrequency::LSRK && freqframe!=MFrequency::Undefined && freqframe!=MFrequency::REST ) 
    1324           0 :       { itsCoordSys.setSpectralConversion("LSRK"); }
    1325           7 :     CoordinateSystem cimageCoord = StokesImageUtil::CStokesCoord( itsCoordSys,
    1326           7 :                                                                   whichStokes, itsDataPolRep);
    1327           7 :     cimageCoord.setObsInfo(itsCoordSys.obsInfo());
    1328           7 :     cimageShape(2)=whichStokes.nelements();
    1329             :     //cout << "Making backward grid of shape : " << cimageShape << " for imshape : " << itsImageShape << endl;
    1330           7 :     itsBackwardGrid.reset( new TempImage<Complex>(TiledShape(cimageShape, tileShape()), cimageCoord, memoryBeforeLattice()) );
    1331             :     //if(image())
    1332           7 :     if(hasRestored()){
    1333           0 :       LatticeLocker lock1(*itsBackwardGrid, FileLocker::Write);
    1334           0 :       itsBackwardGrid->setImageInfo((image())->imageInfo());
    1335           0 :     }
    1336           7 :     return itsBackwardGrid;
    1337           7 :     }
    1338          40 :   Double SIImageStore::memoryBeforeLattice(){
    1339             :           //Calculate how much memory to use per temporary images before disking
    1340          40 :     return 1.0;  /// in MB
    1341             :   }
    1342          40 :   IPosition SIImageStore::tileShape(){
    1343             :           //Need to have settable stuff here or algorith to determine this
    1344          40 :           return IPosition(4, min(itsImageShape[0],1000), min(itsImageShape[1],1000), 1, 1);
    1345             :   }
    1346             : 
    1347             :   // TODO : Move to an image-wrapper class ? Same function exists in SynthesisDeconvolver.
    1348         412 :   Bool SIImageStore::doesImageExist(String imagename)
    1349             :   {
    1350         824 :     LogIO os( LogOrigin("SIImageStore","doesImageExist",WHERE) );
    1351         412 :     Directory image( imagename );
    1352         824 :     return image.exists();
    1353         412 :   }
    1354             : 
    1355             : 
    1356           0 :   void SIImageStore::resetImages( Bool resetpsf, Bool resetresidual, Bool resetweight )
    1357             :   {
    1358           0 :     if( resetpsf ){
    1359           0 :       LatticeLocker lock1(*(psf()), FileLocker::Write);
    1360           0 :       psf()->set(0.0);
    1361             : 
    1362           0 :     }
    1363           0 :     if( resetresidual ) {
    1364             :       //      removeMask( residual() );
    1365           0 :       LatticeLocker lock1(*(residual()), FileLocker::Write);
    1366           0 :       residual()->set(0.0);
    1367           0 :     }
    1368           0 :     if( resetweight && itsWeight ){
    1369           0 :       LatticeLocker lock1(*(weight()), FileLocker::Write);
    1370           0 :       weight()->set(0.0);
    1371           0 :     }
    1372           0 :     if( resetweight ){
    1373           0 :       LatticeLocker lock1(*(sumwt()), FileLocker::Write);
    1374           0 :       sumwt()->set(0.0);
    1375           0 :     }
    1376           0 :   }
    1377             : 
    1378           0 :   void SIImageStore::addImages( std::shared_ptr<SIImageStore> imagestoadd,
    1379             :                                 Bool addpsf, Bool addresidual, Bool addweight, Bool adddensity)
    1380             :   {
    1381             : 
    1382           0 :     if(addpsf)
    1383             :       {
    1384           0 :         LatticeExpr<Float> adderPsf( *(psf()) + *(imagestoadd->psf()) ); 
    1385           0 :         psf()->copyData(adderPsf);
    1386           0 :       }
    1387           0 :     if(addresidual)
    1388             :       {
    1389           0 :         LatticeExpr<Float> adderRes( *(residual()) + *(imagestoadd->residual()) ); 
    1390           0 :         residual()->copyData(adderRes);
    1391           0 :       }
    1392           0 :     if(addweight)
    1393             :       {
    1394           0 :         if( getUseWeightImage( *(imagestoadd->sumwt()) ) ) // Access and add weight only if it is needed.
    1395             :           {
    1396           0 :             LatticeExpr<Float> adderWeight( *(weight()) + *(imagestoadd->weight()) ); 
    1397           0 :             weight()->copyData(adderWeight);
    1398           0 :           }
    1399             : 
    1400             :         /*
    1401             :         Array<Float> qqq, www;
    1402             :         imagestoadd->sumwt()->get(qqq,True);
    1403             :         sumwt()->get(www,True);
    1404             :         cout << "SUMWT : Adding : " << qqq << " to " << www << endl;
    1405             :         */
    1406             : 
    1407           0 :         LatticeExpr<Float> adderSumWt( *(sumwt()) + *(imagestoadd->sumwt()) ); 
    1408           0 :         sumwt()->copyData(adderSumWt);
    1409           0 :         setUseWeightImage( *sumwt(),  getUseWeightImage(*(imagestoadd->sumwt()) ) );
    1410             : 
    1411           0 :       }
    1412           0 :     if(adddensity)
    1413             :       {
    1414           0 :         LatticeExpr<Float> adderDensity( *(gridwt()) + *(imagestoadd->gridwt()) ); 
    1415           0 :         gridwt()->copyData(adderDensity);
    1416           0 :       }
    1417             : 
    1418           0 :   }
    1419             : 
    1420           0 : void SIImageStore::setWeightDensity( std::shared_ptr<SIImageStore> imagetoset )
    1421             :   {
    1422           0 :     LogIO os( LogOrigin("SIImageStore","setWeightDensity",WHERE) );
    1423             :     //gridwt()->copyData( LatticeExpr<Float> ( *(imagetoset->gridwt()) ) );
    1424             :     //looks like you have to call them before hand or it crashes in parallel sometimes
    1425           0 :     IPosition shape=(imagetoset->gridwt())->shape();
    1426           0 :     os << LogIO::DEBUG2 << "SHAPES " << imagetoset->gridwt()->shape() << "   " << gridwt()->shape() << endl;
    1427           0 :     (gridwt(shape))->copyData( LatticeExpr<Float> ( *(imagetoset->gridwt()) ) );
    1428             : 
    1429           0 :   }
    1430             : 
    1431             :   // TODO
    1432             :   //    cout << "WARN :   get getPbMax right for cube.... weight is indexed on chan and pol." << endl;
    1433           0 :   Double SIImageStore::getPbMax()
    1434             :   {
    1435             : 
    1436             :     //// Don't do any extra norm. Minor cycle will operate with native PB.
    1437             :     //return 1.0;
    1438             : 
    1439             :     //// Normalize PB to 1 at the center of the image OF CHANNEL ZERO
    1440             :     
    1441             :     //        IPosition shp = weight(0)->shape();
    1442             :     //     IPosition center(4, shp[0]/2, shp[1]/2,0,0);
    1443             :     //    return sqrt(   weight(0)->getAt( center )   );
    1444             :     
    1445             : 
    1446             :     //// Normalize PB to 1 at the location of the maximum (across all chans..)
    1447             :     
    1448           0 :     LatticeExprNode le( sqrt(max( *(weight(0)) )) );
    1449           0 :     return le.getFloat();
    1450             :     
    1451           0 :   }
    1452             : 
    1453          42 :   Double SIImageStore::getPbMax(Int pol,Int chan)
    1454             :   {
    1455             : 
    1456             :     //// Normalize PB to 1 at the location of the maximum (per pol,chan)
    1457             :     
    1458          42 :     CountedPtr<ImageInterface<Float> > subim=makeSubImage(0, 1,
    1459          42 :                                                           chan, itsImageShape[3],
    1460          42 :                                                           pol, itsImageShape[2],
    1461          84 :                                                           *weight(0));
    1462             : 
    1463          84 :     return sqrt(max(subim->get()));
    1464          42 :   }
    1465             : 
    1466           3 :   void  SIImageStore::makePBFromWeight(const Float pblimit)
    1467             :   {
    1468           6 :    LogIO os( LogOrigin("SIImageStore","makePBFromWeight",WHERE) );
    1469             : 
    1470           6 :         for(Int pol=0; pol<itsImageShape[2]; pol++)
    1471             :           {
    1472           9 :                for(Int chan=0; chan<itsImageShape[3]; chan++)
    1473             :               {
    1474             : 
    1475           6 :                 itsPBScaleFactor = getPbMax(pol,chan);
    1476             :                 
    1477           6 :                 if(itsPBScaleFactor<=0){os << LogIO::NORMAL1 << "Skipping normalization for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;}
    1478             :                 else {
    1479             : 
    1480           3 :                   CountedPtr<ImageInterface<Float> > wtsubim=makeSubImage(0,1, 
    1481           3 :                                                                           chan, itsImageShape[3],
    1482           3 :                                                                           pol, itsImageShape[2], 
    1483           6 :                                                                           *weight() );
    1484           3 :                   CountedPtr<ImageInterface<Float> > pbsubim=makeSubImage(0,1, 
    1485           3 :                                                                           chan, itsImageShape[3],
    1486           3 :                                                                           pol, itsImageShape[2], 
    1487           6 :                                                                           *pb() );
    1488             :                   
    1489             :                   
    1490           6 :                   LatticeExpr<Float> normed( sqrt(abs(*wtsubim)) / itsPBScaleFactor  );
    1491           6 :                   LatticeExpr<Float> limited( iif( normed > fabs(pblimit) , normed, 0.0 ) );
    1492           3 :                   pbsubim->copyData( limited );
    1493           3 :                 }// if not zero
    1494             :               }
    1495             :           }
    1496             : 
    1497           3 :         if((pb()->getDefaultMask()==""))
    1498             :           {
    1499             :             //Remove the old mask as it is no longer valid
    1500             :             //removeMask( pb() );
    1501             : 
    1502             :             //      if( pblimit >= 0.0 )
    1503             :               {
    1504             :                 //MSK// 
    1505           6 :                 LatticeExpr<Bool> pbmask( iif( *pb() > fabs(pblimit) , True , False ) );
    1506             :                 //MSK// 
    1507           3 :                 createMask( pbmask, pb() );
    1508           3 :                 pb()->pixelMask().unlock();
    1509           3 :               }
    1510             : 
    1511             :           }
    1512           3 :         weight()->unlock();
    1513           3 :         pb()->unlock();
    1514           3 :   }
    1515             : 
    1516           4 :   void  SIImageStore::makePBImage(const Float pblimit)
    1517             :   {
    1518           8 :    LogIO os( LogOrigin("SIImageStore","makePBImage",WHERE) );
    1519             : 
    1520           4 :    if( hasPB() )
    1521             :      {
    1522             : 
    1523           8 :         for(Int pol=0; pol<itsImageShape[2]; pol++)
    1524             :           {
    1525          14 :                for(Int chan=0; chan<itsImageShape[3]; chan++)
    1526             :               {
    1527             : 
    1528          10 :                   CountedPtr<ImageInterface<Float> > pbsubim=makeSubImage(0,1, 
    1529          10 :                                                                           chan, itsImageShape[3],
    1530          10 :                                                                           pol, itsImageShape[2], 
    1531          20 :                                                                           *pb() );
    1532             : 
    1533             :                   // Norm by the max
    1534          10 :                   LatticeExprNode elmax= max( *pbsubim );
    1535          10 :                   Float fmax = abs(elmax.getFloat());
    1536             :                   //If there are multiple overlap of beam such that the peak is larger than 1 then normalize
    1537             :                   //otherwise leave as is
    1538          10 :                   if(fmax>1.0)
    1539             :                     {
    1540           0 :                       LatticeExpr<Float> normed( (*pbsubim) / fmax  );
    1541           0 :                       LatticeExpr<Float> limited( iif( normed > fabs(pblimit) , normed, 0.0 ) );
    1542           0 :                       pbsubim->copyData( limited );
    1543           0 :                     }
    1544             :                   else
    1545             :                     {
    1546          20 :                       LatticeExpr<Float> limited( iif((*pbsubim) > fabs(pblimit) , (*pbsubim), 0.0 ) );
    1547          10 :                       pbsubim->copyData( limited );
    1548          10 :                     }
    1549          10 :               }
    1550             :           }
    1551             : 
    1552           4 :         if((pb()->getDefaultMask()==""))// && pblimit >= 0.0)
    1553             :           {
    1554             :             //      removeMask( pb() );
    1555             :             //MSK//             
    1556           8 :             LatticeExpr<Bool> pbmask( iif( *pb() > fabs(pblimit) , True , False ) );
    1557             :             //MSK// 
    1558           4 :             createMask( pbmask, pb() );
    1559           4 :             pb()->pixelMask().unlock();
    1560           4 :           }
    1561             : 
    1562             :      }// if hasPB
    1563           4 :    pb()->unlock();
    1564             : 
    1565           4 :   }
    1566             : 
    1567           9 :   Bool SIImageStore::createMask(LatticeExpr<Bool> &lemask, 
    1568             :                                 CountedPtr<ImageInterface<Float> > outimage)
    1569             :   {
    1570             :     //cout << "Calling makeMask for mask0 for " << outimage->name() << endl;
    1571             :     try
    1572             :       {
    1573           9 :         LatticeLocker lock1(*outimage, FileLocker::Write);
    1574           9 :         ImageRegion outreg = outimage->makeMask("mask0",False,True);
    1575           9 :         LCRegion& outmask=outreg.asMask();
    1576           9 :         outmask.copyData(lemask);
    1577           9 :         outimage->defineRegion("mask0",outreg, RegionHandler::Masks, True);
    1578             :         
    1579           9 :         outimage->setDefaultMask("mask0");
    1580             :         
    1581           9 :         outimage->unlock();
    1582           9 :         outimage->tempClose();
    1583             :         
    1584             :         //    outimage->table().unmarkForDelete();      
    1585           9 :       }
    1586           0 :     catch (const AipsError& x) {
    1587           0 :       throw(AipsError("Error in creating internal T/F mask : " + x.getMesg() ));
    1588           0 :     }
    1589             : 
    1590           9 :     return True;
    1591             :   }
    1592             : 
    1593          15 :   Bool SIImageStore::copyMask(CountedPtr<ImageInterface<Float> > inimage,
    1594             :                                 CountedPtr<ImageInterface<Float> > outimage)
    1595             :   {
    1596             :     //    cout << "In copyMask for " << outimage->name() << endl;
    1597             : 
    1598             :     try
    1599             :       {
    1600          15 :         if( (inimage->getDefaultMask()).matches("mask0") ) // input mask exists.
    1601          12 :           {LatticeLocker lock1(*outimage, FileLocker::Write);
    1602          12 :             removeMask(outimage);
    1603             :             
    1604             :             // // clear output image mask
    1605             :             // if( (outimage->getDefaultMask()).matches("mask0") ) 
    1606             :             //   {outimage->setDefaultMask(""); 
    1607             :             //  outimage->removeRegion("mask0");}
    1608             :             // get mask from input image
    1609             :             
    1610          12 :             ImageRegion outreg=outimage->makeMask("mask0", False, True);
    1611          12 :             LCRegion& outmask=outreg.asMask();
    1612          12 :             outmask.copyData(inimage->getRegion("mask0").asLCRegion());
    1613          12 :             outimage->defineRegion("mask0",outreg, RegionHandler::Masks,True);
    1614          12 :             outimage->setDefaultMask("mask0");
    1615          12 :           }
    1616             :       }
    1617           0 :     catch (const AipsError& x) {
    1618           0 :       throw(AipsError("Error in copying internal T/F mask : " + x.getMesg() ));
    1619           0 :     }
    1620             : 
    1621          15 :     return True;
    1622             :   }
    1623             :   
    1624          14 :   void SIImageStore::removeMask(CountedPtr<ImageInterface<Float> > im)
    1625             :   {
    1626             :     try
    1627             :       {
    1628             :         // // clear output image mask
    1629             :         // if( (im->getDefaultMask()).matches("mask0") ) 
    1630             :         //   {im->setDefaultMask(""); 
    1631             :         //      im->removeRegion("mask0");}
    1632             :         ///Remove the old mask as it is no longer valid
    1633          14 :         LatticeLocker lock1(*im, FileLocker::Write);
    1634          14 :         if (im-> getDefaultMask() != String(""))
    1635             :           {
    1636           6 :             String strung=im->getDefaultMask();
    1637           6 :             im->setDefaultMask("");
    1638           6 :             im->removeRegion(strung);
    1639           6 :           } 
    1640          14 :         if( im->hasRegion("mask0") )
    1641             :           {
    1642           0 :             im->removeRegion("mask0");
    1643             :           }
    1644          14 :       }
    1645           0 :     catch (const AipsError& x)
    1646             :       {
    1647           0 :         throw(AipsError("Error in deleting internal T/F mask : " + x.getMesg() ));
    1648           0 :       }
    1649          14 :   } 
    1650           0 :   void SIImageStore:: rescaleResolution(Int chan, 
    1651             :                                         ImageInterface<Float>& image, 
    1652             :                                         const GaussianBeam& newbeam, 
    1653             :                                         const GaussianBeam& oldbeam){
    1654             : 
    1655           0 :     LogIO os( LogOrigin("SIImageStore","rescaleResolution",WHERE) );
    1656           0 :     GaussianBeam toBeUsed(Quantity(0.0, "arcsec"),Quantity(0.0, "arcsec"), 
    1657           0 :                           Quantity(0.0, "deg")) ;
    1658             :     try {
    1659           0 :       Bool samesize = GaussianDeconvolver::deconvolve(toBeUsed, newbeam, oldbeam);
    1660             : 
    1661             :       /*
    1662             :       os << LogIO::NORMAL2 << "Chan : " << chan << " : Input beam : : " << oldbeam.getMajor(Unit("arcsec")) << " arcsec, " << oldbeam.getMinor(Unit("arcsec"))<< " arcsec, " << oldbeam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    1663             :       os << LogIO::NORMAL2 << "Target beam : " << newbeam.getMajor(Unit("arcsec")) << " arcsec, " << newbeam.getMinor(Unit("arcsec"))<< " arcsec, " << newbeam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    1664             :       os << LogIO::NORMAL2 << "Beam to be used : " << toBeUsed.getMajor(Unit("arcsec")) << " arcsec, " << toBeUsed.getMinor(Unit("arcsec"))<< " arcsec, " << toBeUsed.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    1665             :       os << LogIO::NORMAL2 << "SameSize ? " << samesize << endl;
    1666             :       */
    1667             :       
    1668           0 :       if( samesize )
    1669             :         {
    1670           0 :           os << LogIO::NORMAL2 << "Input and output beam sizes are the same for Channel : " << chan << ". Not convolving residuals." << LogIO::POST;
    1671             :         }
    1672             :         else 
    1673             :         {
    1674           0 :           Double pixwidth=sqrt(image.coordinates().increment()(0)*image.coordinates().increment()(0)+image.coordinates().increment()(1)*image.coordinates().increment()(1));
    1675             :           
    1676           0 :           if(toBeUsed.getMinor(image.coordinates().worldAxisUnits()[0]) > pixwidth)
    1677             :             {
    1678             :               //cerr << "old beam area " << oldbeam.getArea("rad2") << " new beam " << newbeam.getArea("rad2") << endl;
    1679           0 :               StokesImageUtil::Convolve(image, toBeUsed, True);
    1680           0 :               image.copyData(LatticeExpr<Float>(image*newbeam.getArea("rad2")/ oldbeam.getArea("rad2")));
    1681             :             }
    1682             :         }
    1683             :     }
    1684           0 :     catch (const AipsError& x) {
    1685             :       //throw(AipsError("Cannot convolve to new beam: may be smaller than old beam : " + x.getMesg() ));
    1686           0 :       os << LogIO::WARN << "Cannot convolve to new beam for Channel : " << chan <<  " : " << x.getMesg() << LogIO::POST;
    1687           0 :     }
    1688             :     
    1689             : 
    1690           0 :   }
    1691             : 
    1692           7 :   void SIImageStore::divideWeightBySumwt()
    1693             :   {
    1694          14 :     LogIO os(LogOrigin("SIImageStore", "divideWeightBySumWt", WHERE));
    1695             : 
    1696             :    
    1697           7 :     if( itsUseWeight )
    1698             :     { 
    1699             : 
    1700           3 :       divideImageByWeightVal( *weight() ); 
    1701             :     }
    1702             : 
    1703           7 :   }
    1704             :   
    1705             : 
    1706           6 :   void SIImageStore::dividePSFByWeight(const Float /* pblimit*/)
    1707             :   {
    1708          12 :     LogIO os( LogOrigin("SIImageStore","dividePSFByWeight",WHERE) );
    1709             : 
    1710           6 :     LatticeLocker lock1 (*(psf()), FileLocker::Write);
    1711           6 :     normPSF();
    1712             :     //This bit us twice now...hiding this sensitivity division in psf division has wasted a few FTE days
    1713             :     // Leaving it commented so as it is a lesson of not what to do...
    1714             :     // moving it to its own function
    1715             :       //  if( itsUseWeight )
    1716             :    // { 
    1717             :         
    1718             :         //divideImageByWeightVal( *weight() ); 
    1719             :   //  }
    1720           6 :     (psf())->unlock();
    1721             :     
    1722           6 :   }
    1723             : 
    1724           6 :   void SIImageStore::normalizePrimaryBeam(const Float pblimit)
    1725             :   {
    1726          12 :     LogIO os( LogOrigin("SIImageStore","normalizePrimaryBeam",WHERE) );
    1727             : 
    1728             :     //    cout << "In dividePSFByWeight : itsUseWeight : " << itsUseWeight << endl;
    1729           6 :     if( itsUseWeight )
    1730             :     { 
    1731             :         
    1732           6 :         for(Int pol=0; pol<itsImageShape[2]; pol++)
    1733             :           {
    1734           9 :             for(Int chan=0; chan<itsImageShape[3]; chan++)
    1735             :               {
    1736           6 :                 os << LogIO::NORMAL1 << "Scale factor for [C" +String::toString(chan) + ":P" + String::toString(pol) + "] to keep the model image w.r.to a PB of max=1 is " << getPbMax(pol,chan) << LogIO::POST;
    1737             :               }//chan
    1738             :           }//pol
    1739             : 
    1740           3 :         makePBFromWeight(pblimit);
    1741             :         
    1742             :     }//if itsUseWeight
    1743           3 :     else { makePBImage(pblimit); } // OR... just check that it exists already.
    1744           6 :     pb()->unlock();
    1745             :     
    1746           6 :    }
    1747             : 
    1748             :   // Make another for the PSF too.
    1749          15 :   void SIImageStore::divideResidualByWeight(Float pblimit, String normtype) {
    1750             : 
    1751          30 :     LogIO os(LogOrigin("SIImageStore", "divideResidualByWeight", WHERE));
    1752          15 :     LatticeLocker lock1(*(residual()), FileLocker::Write);
    1753             : 
    1754           9 :     auto logTemplate = [&](Int const &chan, Int const &pol, string const &normalizer, string const &result) {
    1755           9 :       os << LogIO::NORMAL1
    1756          18 :          << "[C" + String::toString(chan) + ":P" + String::toString(pol) + "] "
    1757          18 :          << "Dividing " << itsImageName + String(".residual") << " by "
    1758             :          << "[ " << normalizer << " ] "
    1759          27 :          << "to get " << result << "." << LogIO::POST;
    1760           9 :     };
    1761             : 
    1762             :     // Normalize by the sumwt, per plane. 
    1763          15 :     Bool didNorm = divideImageByWeightVal(*residual());
    1764             : 
    1765          15 :     if (itsUseWeight) {
    1766          18 :       for (Int pol = 0; pol < itsImageShape[2]; pol++) {
    1767          27 :         for (Int chan = 0; chan < itsImageShape[3]; chan++) {
    1768          18 :           itsPBScaleFactor = getPbMax(pol, chan);
    1769             : 
    1770          18 :           if (itsPBScaleFactor <= 0) {
    1771             :             os << LogIO::NORMAL1 
    1772             :                << "Skipping normalization for C:" << chan << " P:" << pol 
    1773           9 :                << " because pb max is zero " << LogIO::POST;
    1774             : 
    1775             :           } else {
    1776           9 :             CountedPtr<ImageInterface<Float> > wtsubim = makeSubImage(0, 1,
    1777           9 :                                                                       chan, itsImageShape[3],
    1778           9 :                                                                       pol, itsImageShape[2], 
    1779          18 :                                                                       *weight());
    1780           9 :             CountedPtr<ImageInterface<Float> > ressubim = makeSubImage(0, 1,
    1781           9 :                                                                        chan, itsImageShape[3],
    1782           9 :                                                                        pol, itsImageShape[2], 
    1783          18 :                                                                        *residual());
    1784           9 :             LatticeExpr<Float> ratio;
    1785           9 :             Float scalepb = 1.0;
    1786             : 
    1787           9 :             if (normtype == "flatnoise") {
    1788          27 :               logTemplate(chan, pol,
    1789          18 :                           "sqrt(weightimage) * " + String::toString(itsPBScaleFactor),
    1790             :                           "flat noise with unit pb peak");
    1791             : 
    1792          18 :               LatticeExpr<Float> deno =  itsPBScaleFactor * sqrt(abs(LatticeExpr<Float>(*(wtsubim))));
    1793           9 :               scalepb = fabs(pblimit) * itsPBScaleFactor * itsPBScaleFactor;
    1794           9 :               ratio = iif(deno > scalepb, (*(ressubim) / deno), 0.0);
    1795             : 
    1796           9 :             } else if (normtype == "pbsquare") {
    1797           0 :               logTemplate(chan, pol,
    1798           0 :                           String::toString(itsPBScaleFactor),
    1799             :                           "optimal noise with unit pb peak");
    1800             : 
    1801           0 :               Float deno = itsPBScaleFactor * itsPBScaleFactor;
    1802           0 :               ratio = (*(ressubim) / deno);
    1803             : 
    1804           0 :             } else if (normtype == "flatsky") {
    1805           0 :               logTemplate(chan, pol, "weight", "flat sky");
    1806             : 
    1807           0 :               LatticeExpr<Float> deno = LatticeExpr<Float>(*(wtsubim));
    1808           0 :               scalepb = fabs(pblimit * pblimit) * itsPBScaleFactor * itsPBScaleFactor;
    1809           0 :               ratio = iif(deno > scalepb, (*(ressubim) / deno), 0.0);
    1810             : 
    1811           0 :             }
    1812             : 
    1813             :             //IPosition ip(4, itsImageShape[0] / 2, itsImageShape[1]/2, 0, 0);
    1814             :             //Float resval = ressubim->getAt(ip);
    1815             :             //LatticeExpr<Float> mask(iif((deno) > scalepb, 1.0, 0.0));
    1816             :             //LatticeExpr<Float> maskinv(iif((deno) > scalepb, 0.0, 1.0));
    1817             :             //LatticeExpr<Float> ratio(((*(ressubim)) * mask) / (deno + maskinv));
    1818             : 
    1819             :             //above blocks all sources outside minpb but visible with weight coverage
    1820             :             //which could be cleaned out...one could use below for that
    1821             :             //LatticeExpr<Float> ratio(iif(deno > scalepb, (*(ressubim)) / deno, *ressubim));
    1822             : 
    1823           9 :             ressubim->copyData(ratio);
    1824             : 
    1825             :             //cout << "Val of residual before|after normalizing at center for pol " << pol << " chan " << chan << " : " << resval << "|" << ressubim->getAt(ip) << " weight : " << wtsubim->getAt(ip) << endl;
    1826           9 :           } // if not zero
    1827             :         } //chan
    1828             :       } //pol
    1829             :     }
    1830             :     
    1831             :     // If no normalization happened, print a warning. The user must check if it's right or not.
    1832             :     // Or... later if we get a gridder that does pre-norms, this warning can go. 
    1833          15 :     if ((didNorm | itsUseWeight) != True) {
    1834           0 :       os << LogIO::WARN << "No normalization done to residual" << LogIO::POST;
    1835             :     }
    1836             :     
    1837             :     ///// A T/F mask in the residual will confuse users looking at the interactive clean
    1838             :     ///// window
    1839          15 :     if ((residual()->getDefaultMask() == "") && hasPB() && pblimit >=0.0) {
    1840           0 :       copyMask(pb(), residual());
    1841             :     }
    1842             : 
    1843          15 :     if ((pblimit < 0.0) && (residual()->getDefaultMask()).matches("mask0")) {
    1844           0 :       removeMask(residual());
    1845             :     }
    1846             : 
    1847          15 :     residual()->unlock();
    1848          15 :   }
    1849             : 
    1850           7 :   void SIImageStore::divideResidualByWeightSD(Float pblimit) {
    1851             : 
    1852          14 :     LogIO os(LogOrigin("SIImageStore", "divideResidualByWeightSD", WHERE));
    1853           7 :     LatticeLocker lock1(*(residual()), FileLocker::Write);
    1854             : 
    1855           7 :     if (itsUseWeight) {
    1856          14 :       LatticeExpr<Float> deno = LatticeExpr<Float>(*weight());
    1857          14 :       LatticeExpr<Float> ratio = iif(deno > 0.0, *(residual()) / deno, 0.0);
    1858           7 :       residual()->copyData(ratio);
    1859           7 :     }
    1860             :     else {
    1861             :       // If no normalization happened, print a warning. The user must check if it's right or not.
    1862             :       // Or... later if we get a gridder that does pre-norms, this warning can go.
    1863           0 :       os << LogIO::WARN << "No normalization done to residual" << LogIO::POST;
    1864             :     }
    1865             : 
    1866             :     ///// A T/F mask in the residual will confuse users looking at the interactive clean
    1867             :     ///// window
    1868           7 :     if ((residual()->getDefaultMask() == "") && hasPB() && pblimit >=0.0) {
    1869           0 :       copyMask(pb(), residual());
    1870             :     }
    1871             : 
    1872           7 :     if ((pblimit < 0.0) && (residual()->getDefaultMask()).matches("mask0")) {
    1873           0 :       removeMask(residual());
    1874             :     }
    1875             : 
    1876           7 :     residual()->unlock();
    1877           7 :   }
    1878             : 
    1879           6 :   void SIImageStore::divideModelByWeight(Float pblimit, const String normtype)
    1880             :   {
    1881          12 :     LogIO os( LogOrigin("SIImageStore","divideModelByWeight",WHERE) );
    1882             : 
    1883             :     
    1884          12 :         if(itsUseWeight // only when needed
    1885           6 :            && weight() )// i.e. only when possible. For an initial starting model, don't need wt anyway.
    1886             :       {
    1887             : 
    1888           6 :         if( normtype=="flatsky") {
    1889             :          
    1890           0 :           LatticeExprNode LEN = max( *model());
    1891           0 :           os << LogIO::NORMAL1 << "Model is already flat sky with peak flux : " << LEN.getFloat();
    1892           0 :           os << ". No need to divide before prediction" << LogIO::POST;
    1893             :           
    1894           0 :           return;
    1895           0 :           }
    1896           6 :         else if( normtype=="flatnoise"){
    1897             : 
    1898          12 :           for(Int pol=0; pol<itsImageShape[2]; pol++)
    1899             :             {
    1900          18 :               for(Int chan=0; chan<itsImageShape[3]; chan++)
    1901             :                 {
    1902             :                   
    1903          12 :                   itsPBScaleFactor = getPbMax(pol,chan);
    1904             :                   //    cout << " pbscale : " << itsPBScaleFactor << endl;
    1905          12 :                 if(itsPBScaleFactor<=0){os << LogIO::NORMAL1 << "Skipping normalization for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;}
    1906             :                 else {
    1907             :                   
    1908           6 :                   CountedPtr<ImageInterface<Float> > wtsubim=makeSubImage(0,1, 
    1909           6 :                                                                           chan, itsImageShape[3],
    1910           6 :                                                                           pol, itsImageShape[2], 
    1911          12 :                                                                           *weight() );
    1912           6 :                   CountedPtr<ImageInterface<Float> > modsubim=makeSubImage(0,1, 
    1913           6 :                                                                            chan, itsImageShape[3],
    1914           6 :                                                                            pol, itsImageShape[2], 
    1915          12 :                                                                            *model() );
    1916           6 :                   os << LogIO::NORMAL1 ;
    1917           6 :                   os <<  "[C" +String::toString(chan) + ":P" + String::toString(pol) + "] ";
    1918           6 :                   os << "Dividing " << itsImageName+String(".model") ;
    1919           6 :                   os << " by [ sqrt(weight) / " << itsPBScaleFactor ;
    1920           6 :                   os <<" ] to get to flat sky model before prediction" << LogIO::POST;
    1921             :                   
    1922             :                  
    1923          12 :                   LatticeExpr<Float> deno( sqrt( abs(*(wtsubim)) ) / itsPBScaleFactor );
    1924             :                   
    1925          12 :                   LatticeExpr<Float> mask( iif( (deno) > fabs(pblimit) , 1.0, 0.0 ) );
    1926          12 :                   LatticeExpr<Float> maskinv( iif( (deno) > fabs(pblimit) , 0.0, 1.0 ) );
    1927          12 :                   LatticeExpr<Float> ratio( ( (*(modsubim)) * mask ) / ( deno + maskinv ) );
    1928             :                   
    1929             :                   // 
    1930             :                   //The above has a problem...mask is cutting out clean components found 
    1931             :                   // outside pblimit ...use below if this is what is wanted
    1932             :         //LatticeExpr<Float> ratio(iif(sqrt(abs(*(wtsubim))) < (fabs(pblimit)*itsPBScaleFactor), 0.0,  (*(modsubim))/(sqrt( abs(*(wtsubim)))  / itsPBScaleFactor))); 
    1933             :                   // LatticeExpr<Float> ratio(iif((sqrt(abs(*(wtsubim))) ==0.0), 0.0,  ((*(modsubim))*itsPBScaleFactor)/sqrt( abs(*(wtsubim))) ));
    1934             :                   
    1935           6 :                   IPosition ip(4,itsImageShape[0]/2,itsImageShape[1]/2,0,0);
    1936             :                   ///             Float modval = modsubim->getAt(ip);
    1937             :                   //LatticeExprNode aminval( min(*modsubim) );
    1938             :                   //LatticeExprNode amaxval( max(*modsubim) );
    1939             :                   //cout << "Before ---- min : " << aminval.getFloat() << " max : " << amaxval.getFloat() << endl;
    1940             : 
    1941           6 :                   modsubim->copyData(ratio);
    1942             :                   //              cout << "Val of model before|after flattening at center for pol " << pol << " chan " << chan << " : " << modval << "|" << modsubim->getAt(ip) << " weight : " << wtsubim->getAt(ip) << endl;
    1943             :                   //LatticeExprNode minval( min(*modsubim) );
    1944             :                   //LatticeExprNode maxval( max(*modsubim) );
    1945             :                   //cout << "After ---- min : " << minval.getFloat() << " max : " << maxval.getFloat() << endl;
    1946           6 :                 }// if not zero
    1947             :                 }//chan
    1948             :             }//pol
    1949             : 
    1950             :         }
    1951           0 :         else if( normtype=="pbsquare"){
    1952             : 
    1953           0 :           for(Int pol=0; pol<itsImageShape[2]; pol++)
    1954             :             {
    1955           0 :               for(Int chan=0; chan<itsImageShape[3]; chan++)
    1956             :                 {
    1957             :                   
    1958           0 :                   itsPBScaleFactor = getPbMax(pol,chan);
    1959             :                   //    cout << " pbscale : " << itsPBScaleFactor << endl;
    1960           0 :                 if(itsPBScaleFactor<=0){os << LogIO::NORMAL1 << "Skipping normalization for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;}
    1961             :                 else {
    1962             :                   
    1963           0 :                   CountedPtr<ImageInterface<Float> > wtsubim=makeSubImage(0,1, 
    1964           0 :                                                                           chan, itsImageShape[3],
    1965           0 :                                                                           pol, itsImageShape[2], 
    1966           0 :                                                                           *weight() );
    1967           0 :                   CountedPtr<ImageInterface<Float> > modsubim=makeSubImage(0,1, 
    1968           0 :                                                                            chan, itsImageShape[3],
    1969           0 :                                                                            pol, itsImageShape[2], 
    1970           0 :                                                                            *model() );
    1971           0 :                   os << LogIO::NORMAL1 ;
    1972           0 :                   os <<  "[C" +String::toString(chan) + ":P" + String::toString(pol) + "] ";
    1973           0 :                   os << "Dividing " << itsImageName+String(".model") ;
    1974           0 :                   os << " by [ (weight) / " << itsPBScaleFactor ;
    1975           0 :                   os <<" ] to restore to optimal sky model before prediction" << LogIO::POST;
    1976             :                   
    1977             :                    
    1978           0 :                   LatticeExpr<Float> deno(  abs(*(wtsubim))  / (itsPBScaleFactor*itsPBScaleFactor) );
    1979             :                   
    1980           0 :                   LatticeExpr<Float> mask( iif( (deno) > fabs(pblimit) , 1.0, 0.0 ) );
    1981           0 :                   LatticeExpr<Float> maskinv( iif( (deno) > fabs(pblimit) , 0.0, 1.0 ) );
    1982           0 :                   LatticeExpr<Float> ratio( ( (*(modsubim)) * mask ) / ( deno + maskinv ) );
    1983             :                   
    1984             :                   // 
    1985             :                   //The above has a problem...mask is cutting out clean components found 
    1986             :                   // outside pblimit ...use below if this is what is wanted
    1987             :                   // LatticeExpr<Float> ratio(iif(abs(*(wtsubim)) == 0.0, *modsubim,  (*(modsubim))/( abs(*(wtsubim))  / (itsPBScaleFactor*itsPBScaleFactor)))); 
    1988             :                   
    1989           0 :                   IPosition ip(4,itsImageShape[0]/2,itsImageShape[1]/2,0,0);
    1990             :                   ///             Float modval = modsubim->getAt(ip);
    1991             :                   //LatticeExprNode aminval( min(*modsubim) );
    1992             :                   //LatticeExprNode amaxval( max(*modsubim) );
    1993             :                   //cout << "Before ---- min : " << aminval.getFloat() << " max : " << amaxval.getFloat() << endl;
    1994             : 
    1995           0 :                   modsubim->copyData(ratio);
    1996             :                   
    1997             :                   //              cout << "Val of model before|after flattening at center for pol " << pol << " chan " << chan << " : " << modval << "|" << modsubim->getAt(ip) << " weight : " << wtsubim->getAt(ip) << endl;
    1998             :                   //LatticeExprNode minval( min(*modsubim) );
    1999             :                   //LatticeExprNode maxval( max(*modsubim) );
    2000             :                   //cout << "After ---- min : " << minval.getFloat() << " max : " << maxval.getFloat() << endl;
    2001           0 :                 }// if not zero
    2002             :                 }//chan
    2003             :             }//pol
    2004             : 
    2005             :         }
    2006             : 
    2007             :         //      storeImg(String("flatmodel.im"), *model());
    2008             :         
    2009             :       }
    2010           6 :     }
    2011             :   
    2012           0 :   void SIImageStore::multiplyModelByWeight(Float pblimit, const String normtype)
    2013             :   {
    2014           0 :    LogIO os( LogOrigin("SIImageStore","multiplyModelByWeight",WHERE) );
    2015             : 
    2016           0 :         if(itsUseWeight // only when needed
    2017           0 :            && weight() )// i.e. only when possible. For an initial starting model, don't need wt anyway.
    2018             :       {
    2019           0 :         if( normtype=="flatsky") {
    2020           0 :           os << "Model is already flat sky. No need to multiply back after prediction" << LogIO::POST;
    2021           0 :           return;
    2022             :           }
    2023           0 :         else if( normtype=="flatnoise"){
    2024             : 
    2025           0 :           for(Int pol=0; pol<itsImageShape[2]; pol++)
    2026             :             {
    2027           0 :               for(Int chan=0; chan<itsImageShape[3]; chan++)
    2028             :                 {
    2029             :                   
    2030           0 :                   itsPBScaleFactor = getPbMax(pol,chan);
    2031             :                   //    cout << " pbscale : " << itsPBScaleFactor << endl;
    2032           0 :                 if(itsPBScaleFactor<=0){os << LogIO::NORMAL1 << "Skipping normalization for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;}
    2033             :                 else {
    2034             :                   
    2035           0 :                   CountedPtr<ImageInterface<Float> > wtsubim=makeSubImage(0,1, 
    2036           0 :                                                                           chan, itsImageShape[3],
    2037           0 :                                                                           pol, itsImageShape[2], 
    2038           0 :                                                                           *weight() );
    2039           0 :                   CountedPtr<ImageInterface<Float> > modsubim=makeSubImage(0,1, 
    2040           0 :                                                                            chan, itsImageShape[3],
    2041           0 :                                                                            pol, itsImageShape[2], 
    2042           0 :                                                                            *model() );
    2043             : 
    2044             :                  
    2045             : 
    2046           0 :                   os << LogIO::NORMAL1 ;
    2047           0 :                   os <<  "[C" +String::toString(chan) + ":P" + String::toString(pol) + "] ";
    2048           0 :                   os << "Multiplying " << itsImageName+String(".model") ;
    2049           0 :                   os << " by [ sqrt(weight) / " << itsPBScaleFactor;
    2050           0 :                   os <<  " ] to take model back to flat noise with unit pb peak." << LogIO::POST;
    2051             : 
    2052           0 :                   LatticeExpr<Float> deno( sqrt( abs(*(wtsubim)) ) / itsPBScaleFactor );
    2053             :                   
    2054           0 :                   LatticeExpr<Float> mask( iif( (deno) > fabs(pblimit) , 1.0, 0.0 ) );
    2055           0 :                   LatticeExpr<Float> maskinv( iif( (deno) > fabs(pblimit) , 0.0, 1.0 ) );
    2056           0 :                   LatticeExpr<Float> ratio( ( (*(modsubim)) * mask ) * ( deno + maskinv ) );
    2057             :                  
    2058             :                   /////See comment in divmodel and divresidual for below usage 
    2059             :                   //LatticeExpr<Float> ratio ( (*(modsubim)) * sqrt( abs(*(wtsubim)))  / itsPBScaleFactor );
    2060           0 :                   modsubim->copyData(ratio);
    2061             :       
    2062           0 :                 }// if not zero
    2063             :                 }//chan
    2064             :             }//pol
    2065             :         }
    2066           0 :         else if( normtype=="pbsquare"){
    2067             : 
    2068           0 :           for(Int pol=0; pol<itsImageShape[2]; pol++)
    2069             :             {
    2070           0 :               for(Int chan=0; chan<itsImageShape[3]; chan++)
    2071             :                 {
    2072             :                   
    2073           0 :                   itsPBScaleFactor = getPbMax(pol,chan);
    2074             :                   //    cout << " pbscale : " << itsPBScaleFactor << endl;
    2075           0 :                 if(itsPBScaleFactor<=0){os << LogIO::NORMAL1 << "Skipping normalization for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;}
    2076             :                 else {
    2077             :                   
    2078           0 :                   CountedPtr<ImageInterface<Float> > wtsubim=makeSubImage(0,1, 
    2079           0 :                                                                           chan, itsImageShape[3],
    2080           0 :                                                                           pol, itsImageShape[2], 
    2081           0 :                                                                           *weight() );
    2082           0 :                   CountedPtr<ImageInterface<Float> > modsubim=makeSubImage(0,1, 
    2083           0 :                                                                            chan, itsImageShape[3],
    2084           0 :                                                                            pol, itsImageShape[2], 
    2085           0 :                                                                            *model() );
    2086             : 
    2087             :                  
    2088             : 
    2089           0 :                   os << LogIO::NORMAL1 ;
    2090           0 :                   os <<  "[C" +String::toString(chan) + ":P" + String::toString(pol) + "] ";
    2091           0 :                   os << "Multiplying " << itsImageName+String(".model") ;
    2092           0 :                   os << " by [ weight / " << itsPBScaleFactor*itsPBScaleFactor;
    2093           0 :                   os <<  " ] to take model back to flat noise with unit pb peak." << LogIO::POST;
    2094             :                           
    2095           0 :                   LatticeExpr<Float> deno(  abs(*(wtsubim))  / (itsPBScaleFactor*itsPBScaleFactor) );
    2096             :                   
    2097           0 :                   LatticeExpr<Float> mask( iif( (deno) > fabs(pblimit) , 1.0, 0.0 ) );
    2098           0 :                   LatticeExpr<Float> maskinv( iif( (deno) > fabs(pblimit) , 0.0, 1.0 ) );
    2099           0 :                   LatticeExpr<Float> ratio( ( (*(modsubim)) * mask ) * ( deno + maskinv ) );
    2100             :                  
    2101             :                   /////See comment in divmodel and divresidual for below usage 
    2102             :                   //LatticeExpr<Float> ratio ( (*(modsubim)) * sqrt( abs(*(wtsubim))  / itsPBScaleFactor) );
    2103           0 :                   modsubim->copyData(ratio);
    2104           0 :                 }// if not zero
    2105             :                 }//chan
    2106             :             }//pol
    2107             :         }       
    2108             :       }
    2109           0 :   }
    2110             :   
    2111           0 :   GaussianBeam SIImageStore::getPSFGaussian(Float psfcutoff)
    2112             :   {
    2113           0 :     GaussianBeam beam;
    2114             :     try
    2115             :       {
    2116           0 :         if( psf()->ndim() > 0 )
    2117             :           {
    2118           0 :           LatticeLocker lock2 (*(psf()), FileLocker::Read);
    2119           0 :           StokesImageUtil::FitGaussianPSF( *(psf()), beam, psfcutoff);
    2120           0 :           }
    2121             :       }
    2122           0 :     catch(AipsError &x)
    2123             :       {
    2124             :         //      LogIO os( LogOrigin("SIImageStore","getPSFGaussian",WHERE) );
    2125             :         //      os << "Error in fitting a Gaussian to the PSF : " << x.getMesg() << LogIO::POST;
    2126           0 :         throw( AipsError("Error in fitting a Gaussian to the PSF : " + x.getMesg()) );
    2127           0 :       }
    2128             : 
    2129           0 :     return beam;
    2130           0 :   }
    2131             : 
    2132          23 :   void SIImageStore::makeImageBeamSet(Float psfcutoff, const Bool forcefit)
    2133             :   {
    2134          23 :     clock_t begin = clock();
    2135             :       
    2136          46 :     LogIO os( LogOrigin("SIImageStore","getPSFGaussian",WHERE) );
    2137             :     // For all chans/pols, call getPSFGaussian() and put it into ImageBeamSet(chan,pol).
    2138          23 :     AlwaysAssert( itsImageShape.nelements() == 4, AipsError );
    2139          23 :     uInt nx = itsImageShape[0];
    2140          23 :     uInt ny = itsImageShape[1];
    2141          23 :     uInt npol = itsImageShape[2];
    2142          23 :     uInt nchan = itsImageShape[3];
    2143          23 :     ImageInfo ii = psf()->imageInfo();
    2144          23 :     ImageBeamSet iibeamset=ii.getBeamSet();
    2145          23 :     if(iibeamset.nchan()==nchan && iibeamset.nstokes()==npol && forcefit==False){
    2146          13 :       itsPSFBeams=iibeamset;
    2147          13 :       itsRestoredBeams=iibeamset;
    2148          13 :       return;
    2149             :     }
    2150          10 :     itsPSFBeams.resize( nchan, npol );
    2151          10 :     itsRestoredBeams.resize(nchan, npol);
    2152             :     //    cout << "makeImBeamSet : imshape : " << itsImageShape << endl;
    2153             : 
    2154          10 :     String blankpsfs="";
    2155          33 :     for( uInt chanid=0; chanid<nchan;chanid++) {
    2156          46 :       for( uInt polid=0; polid<npol; polid++ ) {
    2157          23 :     LatticeLocker lock2 (*(psf()), FileLocker::Read);
    2158             : 
    2159          23 :         IPosition substart(4,0,0,polid,chanid);
    2160          23 :         IPosition substop(4,nx-1,ny-1,polid,chanid);
    2161          23 :         Slicer psfslice(substart, substop,Slicer::endIsLast);
    2162          46 :         SubImage<Float> subPsf( *psf() , psfslice, True );
    2163          23 :         GaussianBeam beam;
    2164             : 
    2165          23 :         Bool tryfit=True;
    2166             :         
    2167          23 :         LatticeExprNode le( max(subPsf) );
    2168          23 :         tryfit = le.getFloat()>0.0;
    2169          23 :         if(tryfit)
    2170             :           {
    2171             :             try
    2172             :               {
    2173          15 :                 StokesImageUtil::FitGaussianPSF( subPsf, beam,psfcutoff );
    2174          15 :                 itsPSFBeams.setBeam( chanid, polid, beam );
    2175          15 :                 itsRestoredBeams.setBeam(chanid, polid, beam);
    2176             :               }
    2177           0 :             catch(AipsError &x)
    2178             :               {
    2179           0 :                 os << LogIO::WARN << "[Chan" << chanid << ":Pol" << polid << "] Error Gaussian fit to PSF : " << x.getMesg() ;
    2180             :                 //              os << LogIO::POST;
    2181           0 :                 os << " :  Setting restoring beam to largest valid beam." << LogIO::POST;
    2182           0 :               }
    2183             :           }
    2184             :         else
    2185             :           {
    2186             :             //      os << LogIO::WARN << "[Chan" << chanid << ":Pol" << polid << "] PSF is blank. Setting null restoring beam." << LogIO::POST ;
    2187           8 :             blankpsfs += "[C" +String::toString(chanid) + ":P" + String::toString(polid) + "] ";
    2188             :           }
    2189             : 
    2190          23 :       }// end of pol loop
    2191             :     }// end of chan loop
    2192             : 
    2193          10 :     if( blankpsfs.length() >0 )
    2194           8 :       os << LogIO::WARN << "PSF is blank for" << blankpsfs << LogIO::POST;
    2195             : 
    2196             :     //// Replace null (and bad) beams with the good one. 
    2197             :     ////GaussianBeam maxbeam = findGoodBeam(True);
    2198             : 
    2199             :     //// Replace null beams by a tiny tiny beam, just to get past the ImageInfo restriction that
    2200             :     //// all planes must have non-null beams.
    2201             :     
    2202          10 :     GaussianBeam defaultbeam=itsPSFBeams.getMaxAreaBeam();
    2203             :     ///many of the unittests in tsdimaging seem to depend on having 0 area beams
    2204             :     ///which throws and exception when it is stored in the image
    2205             :     ///(so setting them to some small number)!
    2206          10 :     if(defaultbeam.getArea("rad2")==0.0){
    2207           0 :       Quantity majax(1e-06,"arcsec"),minax(1e-06,"arcsec"),pa(0.0,"deg");
    2208           0 :       defaultbeam.setMajorMinor(majax,minax);
    2209           0 :       defaultbeam.setPA(pa);
    2210           0 :     }
    2211          33 :     for( uInt chanid=0; chanid<nchan;chanid++) {
    2212          46 :       for( uInt polid=0; polid<npol; polid++ ) {
    2213          23 :         if( (itsPSFBeams.getBeam(chanid, polid)).isNull() ) 
    2214           8 :           { itsPSFBeams.setBeam( chanid, polid, defaultbeam );
    2215           8 :             itsRestoredBeams.setBeam( chanid, polid, defaultbeam );
    2216             :           }
    2217             :       }// end of pol loop
    2218             :     }// end of chan loop
    2219             :     
    2220             :     /*        
    2221             :     //// Fill in gaps if there are any --- with the MAX Area beam. 
    2222             :     /////    GaussianBeam maxbeam = itsPSFBeams.getMaxAreaBeam();
    2223             :     if( maxbeam.isNull() ) {
    2224             :         os << LogIO::WARN << "No planes have non-zero restoring beams. Forcing artificial 1.0arcsec beam." << LogIO::POST;
    2225             :         Quantity majax(1.0,"arcsec"),minax(1.0,"arcsec"),pa(0.0,"deg");
    2226             :         maxbeam.setMajorMinor(majax,minax);
    2227             :         maxbeam.setPA(pa);
    2228             :       }
    2229             :     else  {
    2230             :         for( Int chanid=0; chanid<nchan;chanid++) {
    2231             :           for( Int polid=0; polid<npol; polid++ ) {
    2232             :             if( (itsPSFBeams.getBeam(chanid, polid)).isNull() ) 
    2233             :               { itsPSFBeams.setBeam( chanid, polid, maxbeam ); }
    2234             :           }// end of pol loop
    2235             :         }// end of chan loop
    2236             :       }
    2237             :     */
    2238             : 
    2239             : 
    2240             :     /// For lack of a better place, store this inside the PSF image. To be read later and used to restore
    2241             :    
    2242          10 :     ii.setBeams( itsPSFBeams );
    2243             :     {
    2244          10 :       LatticeLocker lock1(*(psf()), FileLocker::Write);
    2245          10 :       psf()->setImageInfo(ii);
    2246          10 :       psf()->unlock();
    2247          10 :     }
    2248          10 :     clock_t end = clock();
    2249          10 :     os << LogIO::NORMAL << "Time to fit Gaussian to PSF " << double(end - begin) / CLOCKS_PER_SEC << LogIO::POST;
    2250          49 :   }// end of make beam set
    2251             : 
    2252             : 
    2253           0 :   ImageBeamSet SIImageStore::getChannelBeamSet(const Int channel){
    2254             : 
    2255           0 :     return getChannelSliceBeamSet(channel, channel);
    2256             :   }
    2257             : 
    2258             : 
    2259           0 :   ImageBeamSet SIImageStore::getChannelSliceBeamSet(const Int begChan, const Int endChan){
    2260           0 :      ImageBeamSet bs=getBeamSet();
    2261           0 :     if(bs.shape()[0]==1)
    2262           0 :       return bs;
    2263           0 :     if(begChan > endChan || begChan <0)
    2264           0 :       throw(AipsError("Inconsistent slice of beam in channel requested"));
    2265           0 :     if(bs.shape()[0] < (endChan-1))
    2266           0 :       throw(AipsError("beam of channel "+String::toString(endChan)+" does not exist"));
    2267           0 :     IPosition blc(2, begChan, 0);
    2268           0 :     IPosition trc(2, endChan, bs.shape()[1]-1);
    2269           0 :     Matrix<GaussianBeam> sliceBeam=bs.getBeams()(blc, trc);
    2270           0 :     ImageBeamSet subBeamSet(sliceBeam);
    2271           0 :     return subBeamSet;
    2272             : 
    2273           0 :   }
    2274           7 :   void SIImageStore::setBeamSet(const ImageBeamSet& bs){
    2275             : 
    2276           7 :     itsPSFBeams=bs;
    2277           7 :   }
    2278             :   
    2279          13 :   ImageBeamSet SIImageStore::getBeamSet(Float psfcutoff)
    2280             :   {
    2281          13 :     IPosition beamshp = itsPSFBeams.shape();
    2282          13 :     AlwaysAssert( beamshp.nelements()==2 , AipsError );
    2283          13 :     if( beamshp[0]==0 || beamshp[1]==0 ) {makeImageBeamSet(psfcutoff);}
    2284          26 :     return itsPSFBeams; 
    2285          13 :   }
    2286             : 
    2287          10 :   void SIImageStore::printBeamSet(Bool verbose)
    2288             :   {
    2289          20 :     LogIO os( LogOrigin("SIImageStore","printBeamSet",WHERE) );
    2290          10 :     AlwaysAssert( itsImageShape.nelements() == 4, AipsError );
    2291          10 :     if( itsImageShape[3] == 1 && itsImageShape[2]==1 )
    2292             :       {
    2293           2 :         GaussianBeam beam = itsPSFBeams.getBeam();
    2294           2 :         os << "Beam : " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2295           2 :  }
    2296             :     else
    2297             :       {
    2298             :         // per CAS-11415, verbose=True when restoringbeam='common'
    2299           8 :         if( verbose ) 
    2300             :           {
    2301           0 :             ostringstream oss;
    2302           0 :             oss<<"Beam";
    2303           0 :             Int nchan = itsImageShape[3];
    2304           0 :             for( Int chanid=0; chanid<nchan;chanid++) {
    2305           0 :               Int polid=0;
    2306             :               //          for( Int polid=0; polid<npol; polid++ ) {
    2307           0 :               GaussianBeam beam = itsPSFBeams.getBeam( chanid, polid );
    2308           0 :               oss << " [C" << chanid << "]: " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg";
    2309           0 :             }//for chanid
    2310           0 :             os << oss.str() << LogIO::POST;
    2311           0 :           }
    2312             :         else 
    2313             :           { 
    2314             :         // TODO : Enable this, when this function doesn't complain about 0 rest freq.
    2315             :         //                                 or when rest freq is never zero !
    2316             :         try{
    2317           8 :                 itsPSFBeams.summarize( os, False, itsCoordSys );
    2318             :                 // per CAS-11415 request, not turn on this one (it prints out per-channel beam in each line in the logger)
    2319             :                 //itsPSFBeams.summarize( os, verbose, itsCoordSys );
    2320             :         }
    2321           0 :         catch(AipsError &x)
    2322             :           {
    2323           0 :             os << LogIO::WARN << "Error while printing (compact) restoring beam summary : " <<  x.getMesg() << LogIO::POST;
    2324           0 :             os << "Printing long summary" << LogIO::POST;
    2325             :             
    2326           0 :             AlwaysAssert( itsImageShape.nelements() == 4, AipsError );
    2327             :             //Int npol = itsImageShape[2];
    2328           0 :             Int nchan = itsImageShape[3];
    2329           0 :             for( Int chanid=0; chanid<nchan;chanid++) {
    2330           0 :               Int polid=0;
    2331             :               //          for( Int polid=0; polid<npol; polid++ ) {
    2332           0 :               GaussianBeam beam = itsPSFBeams.getBeam( chanid, polid );
    2333           0 :               os << "Beam [C" << chanid << "]: " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2334             :               //}//for polid
    2335           0 :             }//for chanid
    2336           0 :           }// catch
    2337             :         }
    2338             :       }
    2339          10 :   }
    2340             :   
    2341             :   /////////////////////////////// Restore all planes.
    2342             : 
    2343           6 :   void SIImageStore::restore(GaussianBeam& rbeam, String& usebeam, uInt term, Float psfcutoff)
    2344             :   {
    2345          12 :     LogIO os( LogOrigin("SIImageStore","restore",WHERE) );
    2346             :     //     << ". Optionally, PB-correct too." << LogIO::POST;
    2347             : 
    2348           6 :     AlwaysAssert( itsImageShape.nelements() == 4, AipsError );
    2349           6 :     Int nx = itsImageShape[0];
    2350           6 :     Int ny = itsImageShape[1];
    2351           6 :     Int npol = itsImageShape[2];
    2352           6 :     Int nchan = itsImageShape[3];
    2353             : 
    2354             :     /*    if( !hasResidualImage() )
    2355             :       {
    2356             :         // Cannot restore without residual/dirty image.
    2357             :         os << "Cannot restore without residual image" << LogIO::POST;
    2358             :         return;
    2359             :       }
    2360             :     */
    2361             : 
    2362             :     //// Get/fill the beamset
    2363           6 :     IPosition beamset = itsPSFBeams.shape();
    2364           6 :     AlwaysAssert( beamset.nelements()==2 , AipsError );
    2365           6 :     if( beamset[0] != nchan || beamset[1] != npol )
    2366             :       {
    2367             :         
    2368             :         // Get PSF Beams....
    2369           1 :         ImageInfo ii = psf()->imageInfo();
    2370           1 :         itsPSFBeams = ii.getBeamSet();
    2371           1 :         itsRestoredBeams=itsPSFBeams;
    2372           1 :         IPosition beamset2 = itsPSFBeams.shape();
    2373             : 
    2374           1 :         AlwaysAssert( beamset2.nelements()==2 , AipsError );
    2375           1 :         if( beamset2[0] != nchan || beamset2[1] != npol )
    2376             :           {
    2377             :             // Make new beams.
    2378           0 :             os << LogIO::WARN << "Couldn't find pre-computed restoring beams. Re-fitting." << LogIO::POST;
    2379           0 :             makeImageBeamSet(psfcutoff);
    2380             :           }
    2381           1 :       }
    2382             : 
    2383             :     // toggle for printing common beam to the log 
    2384           6 :     Bool printcommonbeam(False);
    2385             :     //// Modify the beamset if needed
    2386             :     //// if ( rbeam is Null and usebeam=="" ) Don't do anything.
    2387             :     //// If rbeam is Null but usebeam=='common', calculate a common beam and set 'rbeam'
    2388             :     //// If rbeam is given (or exists due to 'common'), just use it.
    2389           6 :     if( rbeam.isNull() && usebeam=="common") {
    2390           0 :       os << "Getting common beam" << LogIO::POST;
    2391           0 :       rbeam = CasaImageBeamSet(itsPSFBeams).getCommonBeam();
    2392           0 :       os << "Common Beam : " << rbeam.getMajor(Unit("arcsec")) << " arcsec, " << rbeam.getMinor(Unit("arcsec"))<< " arcsec, " << rbeam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2393           0 :       printcommonbeam=True;
    2394             :     }
    2395           6 :     if( !rbeam.isNull() ) {
    2396             :       /*for( Int chanid=0; chanid<nchan;chanid++) {
    2397             :         for( Int polid=0; polid<npol; polid++ ) {
    2398             :           itsPSFBeams.setBeam( chanid, polid, rbeam );
    2399             :           /// Still need to add the 'common beam' option.
    2400             :         }//for chanid
    2401             :       }//for polid
    2402             :       */
    2403           0 :       itsRestoredBeams=ImageBeamSet(rbeam);
    2404           0 :       GaussianBeam beam = itsRestoredBeams.getBeam();
    2405             :      
    2406             :       //if commonbeam has not printed in the log
    2407           0 :       if (!printcommonbeam) {
    2408           0 :         os << "Common Beam : " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2409           0 :       printcommonbeam=True; // to avoid duplicate the info is printed to th elog
    2410             :       }
    2411           0 :     }// if rbeam not NULL
    2412             :     //// Done modifying beamset if needed
    2413             : 
    2414             : 
    2415             :     /// Before restoring, check for an empty model image and don't convolve (but still smooth residuals)
    2416             :     /// (for CAS-8271 : make output restored image even if .model is zero... )
    2417           6 :     Bool emptymodel = isModelEmpty();
    2418           6 :     if(emptymodel) os << LogIO::WARN << "Restoring with an empty model image. Only residuals will be processed to form the output restored image." << LogIO::POST;
    2419             : 
    2420             : 
    2421           6 :     LatticeLocker lock1(*(image(term)), FileLocker::Write);
    2422           6 :     LatticeLocker lock2(*(residual(term)), FileLocker::Write);
    2423           6 :     LatticeLocker lock3(*(model(term)), FileLocker::Read);
    2424             :     //// Use beamset to restore
    2425          17 :     for( Int chanid=0; chanid<nchan;chanid++) {
    2426          22 :       for( Int polid=0; polid<npol; polid++ ) {
    2427             :         
    2428          11 :         IPosition substart(4,0,0,polid,chanid);
    2429          11 :         IPosition substop(4,nx-1,ny-1,polid,chanid);
    2430          11 :         Slicer imslice(substart, substop,Slicer::endIsLast);             
    2431          22 :         SubImage<Float> subRestored( *image(term) , imslice, True );
    2432          22 :         SubImage<Float> subModel( *model(term) , imslice, False );
    2433          22 :         SubImage<Float> subResidual( *residual(term) , imslice, True );
    2434             :         
    2435          11 :         GaussianBeam beam = itsRestoredBeams.getBeam( chanid, polid );;
    2436             :         //os << "Common Beam for chan : " << chanid << " : " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2437             :         // only print per-chan beam if the common beam is not used for restoring beam
    2438          11 :         if(!printcommonbeam) { 
    2439          11 :           os << "Beam for chan : " << chanid << " : " << beam.getMajor(Unit("arcsec")) << " arcsec, " << beam.getMinor(Unit("arcsec"))<< " arcsec, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2440             :         }
    2441             : 
    2442             :         try
    2443             :           {
    2444             :             // Initialize restored image
    2445          11 :             subRestored.set(0.0);
    2446          11 :              if( !emptymodel ) { 
    2447             :                // Copy model into it
    2448          11 :                subRestored.copyData( LatticeExpr<Float>( subModel )  );
    2449             :                // Smooth model by beam
    2450          11 :                StokesImageUtil::Convolve( subRestored, beam);
    2451             :              }
    2452             :             // Add residual image
    2453          11 :             if( !rbeam.isNull() || usebeam == "common") // If need to rescale residuals, make a copy and do it.
    2454             :               {
    2455             :                 //              rescaleResolution(chanid, subResidual, beam, itsPSFBeams.getBeam(chanid, polid));
    2456           0 :                 TempImage<Float> tmpSubResidualCopy( IPosition(4,nx,ny,1,1), subResidual.coordinates());
    2457           0 :                 tmpSubResidualCopy.copyData( subResidual );
    2458             :                 
    2459           0 :                 rescaleResolution(chanid, tmpSubResidualCopy, beam, itsPSFBeams.getBeam(chanid, polid));
    2460           0 :                 subRestored.copyData( LatticeExpr<Float>( subRestored + tmpSubResidualCopy  ) );
    2461           0 :               }
    2462             :             else// if no need to rescale residuals, just add the residuals.
    2463             :               {
    2464             :                 
    2465             :                 
    2466          11 :                 subRestored.copyData( LatticeExpr<Float>( subRestored + subResidual  ) );
    2467             :                 
    2468             :               }
    2469             :             
    2470             :           }
    2471           0 :         catch(AipsError &x)
    2472             :           {
    2473           0 :             throw( AipsError("Restoration Error in chan" + String::toString(chanid) + ":pol" + String::toString(polid) + " : " + x.getMesg() ) );
    2474           0 :           }
    2475             :         
    2476          11 :       }// end of pol loop
    2477             :     }// end of chan loop
    2478             :     
    2479             :     try
    2480             :       {
    2481             :         //MSK// 
    2482           6 :         if( hasPB() )
    2483             :           {
    2484           6 :             if( (image(term)->getDefaultMask()).matches("mask0") ) removeMask( image(term) );
    2485           6 :             copyMask(residual(term),image(term));
    2486             :           }
    2487             : 
    2488             :         //      if(hasPB()){copyMask(residual(term),image(term));}
    2489           6 :         ImageInfo iminf = image(term)->imageInfo();
    2490             :         //iminf.setBeams( itsRestoredBeams);
    2491             : 
    2492           6 :         os << "Beam Set : Single beam : " << itsRestoredBeams.hasSingleBeam() << "  Multi-beam : " << itsRestoredBeams.hasMultiBeam() << LogIO::DEBUG2;
    2493             : 
    2494           6 :         iminf.removeRestoringBeam();
    2495             : 
    2496           6 :         if( itsRestoredBeams.hasSingleBeam() )
    2497           2 :           { iminf.setRestoringBeam( itsRestoredBeams.getBeam() );}
    2498             :         else
    2499           4 :           {iminf.setBeams( itsRestoredBeams);}
    2500             : 
    2501           6 :         image(term)->setImageInfo(iminf);
    2502             :  
    2503           6 :       }
    2504           0 :     catch(AipsError &x)
    2505             :       {
    2506           0 :         throw( AipsError("Restoration Error  : "  + x.getMesg() ) );
    2507           0 :       }
    2508             :         
    2509           6 :   }// end of restore()
    2510             : 
    2511           0 :   GaussianBeam SIImageStore::findGoodBeam()
    2512             :   {
    2513           0 :     LogIO os( LogOrigin("SIImageStore","findGoodBeam",WHERE) );
    2514           0 :     IPosition beamshp = itsPSFBeams.shape();
    2515           0 :     AlwaysAssert( beamshp.nelements()==2 , AipsError );
    2516             : 
    2517             :     /*
    2518             :     if( beamshp[0] != nchan || beamshp[1] != npol )
    2519             :       {
    2520             :         // Make new beams.
    2521             :         os << LogIO::WARN << "Couldn't find pre-computed restoring beams. Re-fitting." << LogIO::POST;
    2522             :         makeImageBeamSet();
    2523             :       }
    2524             :     */
    2525             : 
    2526           0 :     Vector<Float> areas(beamshp[0]*beamshp[1]);
    2527           0 :     Vector<Float> axrat(beamshp[0]*beamshp[1]);
    2528           0 :     areas=0.0; axrat=1.0;
    2529           0 :     Vector<Bool> flags( areas.nelements() );
    2530           0 :     flags=False;
    2531             :     
    2532           0 :     Int cnt=0;
    2533           0 :     for( Int chanid=0; chanid<beamshp[0];chanid++) {
    2534           0 :       for( Int polid=0; polid<beamshp[1]; polid++ ) {
    2535           0 :         GaussianBeam beam = itsPSFBeams(chanid, polid);
    2536           0 :         if( !beam.isNull() && beam.getMajor(Unit("arcsec"))>1.1e-06  )  // larger than default filler beam.
    2537             :           {
    2538           0 :             areas[cnt] = beam.getArea( Unit("arcsec2") );
    2539           0 :             axrat[cnt] = beam.getMajor( Unit("arcsec") ) / beam.getMinor( Unit("arcsec") );
    2540             :           }
    2541             :         else {
    2542           0 :           flags[cnt] = True;
    2543             :         }
    2544           0 :         cnt++;
    2545           0 :       }//for chanid
    2546             :     }//for polid
    2547             :     
    2548           0 :     Vector<Float> fit( areas.nelements() );
    2549           0 :     Vector<Float> fitaxr( areas.nelements() );
    2550           0 :     for (Int loop=0;loop<5;loop++)  {
    2551             :       /// Filter on outliers in PSF beam area
    2552           0 :       lineFit( areas, flags, fit, 0, areas.nelements()-1 );
    2553           0 :       Float sd = calcStd( areas , flags, fit );
    2554           0 :       for (uInt  i=0;i<areas.nelements();i++) {
    2555           0 :         if( fabs( areas[i] - fit[i] ) > 3*sd ) flags[i]=True;
    2556             :       }
    2557             :       /// Filter on outliers in PSF axial ratio
    2558           0 :       lineFit( axrat, flags, fitaxr, 0, areas.nelements()-1 );
    2559           0 :       Float sdaxr = calcStd( axrat , flags, fitaxr );
    2560           0 :       for (uInt  i=0;i<areas.nelements();i++) {
    2561           0 :         if( fabs( axrat[i] - fitaxr[i] ) > 3*sdaxr ) flags[i]=True;
    2562             :       }
    2563             :     }
    2564             :     //    cout << "Original areas : " << areas << endl;
    2565             :     //    cout << "Original axrats : " << axrat << endl;
    2566             :     //    cout << "Flags : " << flags << endl;
    2567             : 
    2568             :     // Find max area good beam.
    2569           0 :     GaussianBeam goodbeam;
    2570           0 :     Int cid=0,pid=0;
    2571           0 :     Float maxval=0.0;
    2572           0 :     cnt=0;
    2573           0 :     for( Int chanid=0; chanid<beamshp[0];chanid++) {
    2574           0 :       for( Int polid=0; polid<beamshp[1]; polid++ ) {
    2575           0 :         if( flags[cnt] == False ){ 
    2576           0 :           if( areas[cnt] > maxval ) {maxval = areas[cnt]; goodbeam = itsPSFBeams.getBeam(chanid,polid);cid=chanid;pid=polid;}
    2577             :         }
    2578           0 :         cnt++;
    2579             :       }//polid
    2580             :     }//chanid
    2581             : 
    2582           0 :     os << "Picking common beam from C"<<cid<<":P"<<pid<<" : " << goodbeam.getMajor(Unit("arcsec")) << " arcsec, " << goodbeam.getMinor(Unit("arcsec"))<< " arcsec, " << goodbeam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2583             : 
    2584           0 :     Bool badbeam=False;
    2585           0 :     for(uInt i=0;i<flags.nelements();i++){if(flags[i]==True) badbeam=True;}
    2586             : 
    2587           0 :     if( badbeam == True ) 
    2588             :       { 
    2589           0 :         os << "(Ignored beams from :";
    2590           0 :         cnt=0;
    2591           0 :         for( Int chanid=0; chanid<beamshp[0];chanid++) {
    2592           0 :           for( Int polid=0; polid<beamshp[1]; polid++ ) {
    2593           0 :             if( flags[cnt] == True ){ 
    2594           0 :               os << " C"<<chanid<<":P"<<polid;
    2595             :             }
    2596           0 :             cnt++;
    2597             :           }//polid
    2598             :         }//chanid
    2599           0 :         os << " as outliers either by area or by axial ratio)" << LogIO::POST;
    2600             :       } 
    2601             : 
    2602             : 
    2603             :     /*
    2604             :     // Replace 'bad' psfs with the chosen one.
    2605             :     if( goodbeam.isNull() ) {
    2606             :       os << LogIO::WARN << "No planes have non-zero restoring beams. Forcing artificial 1.0arcsec beam." << LogIO::POST;
    2607             :       Quantity majax(1.0,"arcsec"),minax(1.0,"arcsec"),pa(0.0,"deg");
    2608             :       goodbeam.setMajorMinor(majax,minax);
    2609             :       goodbeam.setPA(pa);
    2610             :     }
    2611             :     else  {
    2612             :       cnt=0;
    2613             :       for( Int chanid=0; chanid<nchan;chanid++) {
    2614             :         for( Int polid=0; polid<npol; polid++ ) {
    2615             :           if( flags[cnt]==True ) 
    2616             :             { itsPSFBeams.setBeam( chanid, polid, goodbeam ); }
    2617             :           cnt++;
    2618             :         }// end of pol loop
    2619             :       }// end of chan loop
    2620             :     }
    2621             :     */
    2622             : 
    2623           0 :     return goodbeam;
    2624           0 :   }// end of findGoodBeam
    2625             : 
    2626             :   ///////////////////////// Funcs to calculate robust mean and fit, taking into account 'flagged' points.
    2627           0 : void SIImageStore :: lineFit(Vector<Float> &data, Vector<Bool> &flag, Vector<Float> &fit, uInt lim1, uInt lim2)
    2628             : {
    2629           0 :   float Sx = 0, Sy = 0, Sxx = 0, Sxy = 0, S = 0, a, b, sd, mn;
    2630             :   
    2631           0 :   mn = calcMean(data, flag);
    2632           0 :   sd = calcStd (data, flag, mn);
    2633             :   
    2634           0 :   for (uInt i = lim1; i <= lim2; i++)
    2635             :     {
    2636           0 :       if (flag[i] == False) // if unflagged
    2637             :         {
    2638           0 :           S += 1 / (sd * sd);
    2639           0 :           Sx += i / (sd * sd);
    2640           0 :           Sy += data[i] / (sd * sd);
    2641           0 :           Sxx += (i * i) / (sd * sd);
    2642           0 :           Sxy += (i * data[i]) / (sd * sd);
    2643             :         }
    2644             :     }
    2645           0 :   a = (Sxx * Sy - Sx * Sxy) / (S * Sxx - Sx * Sx);
    2646           0 :   b = (S * Sxy - Sx * Sy) / (S * Sxx - Sx * Sx);
    2647             :   
    2648           0 :   for (uInt i = lim1; i <= lim2; i++)
    2649           0 :     fit[i] = a + b * i;
    2650             :   
    2651           0 : }
    2652             : /* Calculate the MEAN of 'vect' ignoring values flagged in 'flag' */
    2653           0 : Float SIImageStore :: calcMean(Vector<Float> &vect, Vector<Bool> &flag)
    2654             : {
    2655           0 :   Float mean=0;
    2656           0 :   Int cnt=0;
    2657           0 :   for(uInt i=0;i<vect.nelements();i++)
    2658           0 :     if(flag[i]==False)
    2659             :       {
    2660           0 :         mean += vect[i];
    2661           0 :         cnt++;
    2662             :       }
    2663           0 :   if(cnt==0) cnt=1;
    2664           0 :   return mean/cnt;
    2665             : }
    2666           0 : Float SIImageStore :: calcStd(Vector<Float> &vect, Vector<Bool> &flag, Vector<Float> &fit)
    2667             : {
    2668           0 :   Float std=0;
    2669           0 :   uInt n=0,cnt=0;
    2670           0 :   n = vect.nelements() < fit.nelements() ? vect.nelements() : fit.nelements();
    2671           0 :   for(uInt i=0;i<n;i++)
    2672           0 :     if(flag[i]==False)
    2673             :       {
    2674           0 :         cnt++;
    2675           0 :         std += (vect[i]-fit[i])*(vect[i]-fit[i]);
    2676             :       }
    2677           0 :   if(cnt==0) cnt=1;
    2678           0 :   return sqrt(std/cnt);
    2679             : 
    2680             : }
    2681           0 : Float SIImageStore :: calcStd(Vector<Float> &vect, Vector<Bool> &flag, Float mean)
    2682             : {
    2683           0 :   Float std=0;
    2684           0 :   uInt cnt=0;
    2685           0 :   for(uInt i=0;i<vect.nelements();i++)
    2686           0 :     if(flag[i]==False)
    2687             :       {
    2688           0 :         cnt++;
    2689           0 :         std += (vect[i]-mean)*(vect[i]-mean);
    2690             :       }
    2691           0 :   return sqrt(std/cnt);
    2692             : }
    2693             : 
    2694             :   ///////////////////////// End of Funcs to calculate robust mean and fit.
    2695             : 
    2696             : 
    2697             : 
    2698             : /*
    2699             :   GaussianBeam SIImageStore::restorePlane()
    2700             :   {
    2701             : 
    2702             :     LogIO os( LogOrigin("SIImageStore","restorePlane",WHERE) );
    2703             :     //     << ". Optionally, PB-correct too." << LogIO::POST;
    2704             : 
    2705             :     Bool validbeam=False;
    2706             :     GaussianBeam beam;
    2707             :     try
    2708             :       {
    2709             :         // Fit a Gaussian to the PSF.
    2710             :         beam = getPSFGaussian();
    2711             :         validbeam = True;
    2712             :       }
    2713             :     catch(AipsError &x)
    2714             :       {
    2715             :         os << LogIO::WARN << "Beam fit error : " + x.getMesg() << LogIO::POST;
    2716             :       }
    2717             :     
    2718             :     try
    2719             :       {
    2720             :         if( validbeam==True )
    2721             :           {
    2722             :             //os << "[" << itsImageName << "] " ;  // Add when parent image name is available.
    2723             :             //os << "Restore with beam : " << beam.getMajor(Unit("arcmin")) << " arcmin, " << beam.getMinor(Unit("arcmin"))<< " arcmin, " << beam.getPA(Unit("deg")) << " deg" << LogIO::POST; 
    2724             :             
    2725             :             // Initialize restored image
    2726             :             image()->set(0.0);
    2727             :             // Copy model into it
    2728             :             image()->copyData( LatticeExpr<Float>( *(model()) )  );
    2729             :             // Smooth model by beam
    2730             :             StokesImageUtil::Convolve( *(image()), beam);
    2731             :             // Add residual image
    2732             :             image()->copyData( LatticeExpr<Float>( *(image()) + *(residual())  ) );
    2733             :             
    2734             :             // Set restoring beam into the image
    2735             :             ImageInfo ii = image()->imageInfo();
    2736             :             //ii.setRestoringBeam(beam);
    2737             :             ii.setBeams(beam);
    2738             :             image()->setImageInfo(ii);
    2739             :           }
    2740             :       }
    2741             :     catch(AipsError &x)
    2742             :       {
    2743             :         throw( AipsError("Restoration Error : " + x.getMesg() ) );
    2744             :       }
    2745             :         
    2746             :     return beam;
    2747             : 
    2748             :   }
    2749             : */
    2750             : 
    2751           0 :   void SIImageStore::pbcor(uInt term)
    2752             :   {
    2753             : 
    2754           0 :     LogIO os( LogOrigin("SIImageStore","pbcor",WHERE) );
    2755             : 
    2756           0 :     if( !hasRestored() || !hasPB() )
    2757             :       {
    2758             :         // Cannot pbcor without restored image and pb
    2759           0 :         os << LogIO::WARN << "Cannot pbcor without restored image and pb" << LogIO::POST;
    2760           0 :         return;
    2761             :       }
    2762           0 :     LatticeLocker lock1(*(image(term)), FileLocker::Write);
    2763           0 :         LatticeLocker lock2(*(pb(term)), FileLocker::Write);
    2764           0 :         LatticeLocker lock3(*(imagepbcor(term)), FileLocker::Write);
    2765             : 
    2766           0 :         for(Int pol=0; pol<itsImageShape[2]; pol++)
    2767             :           {
    2768           0 :             for(Int chan=0; chan<itsImageShape[3]; chan++)
    2769             :               {
    2770             :                 
    2771           0 :                 CountedPtr<ImageInterface<Float> > restoredsubim=makeSubImage(0,1, 
    2772           0 :                                                                       chan, itsImageShape[3],
    2773           0 :                                                                       pol, itsImageShape[2], 
    2774           0 :                                                                       *image(term) );
    2775           0 :                 CountedPtr<ImageInterface<Float> > pbsubim=makeSubImage(0,1, 
    2776           0 :                                                                       chan, itsImageShape[3],
    2777           0 :                                                                       pol, itsImageShape[2], 
    2778           0 :                                                                       *pb() );
    2779             : 
    2780           0 :                 CountedPtr<ImageInterface<Float> > pbcorsubim=makeSubImage(0,1, 
    2781           0 :                                                                       chan, itsImageShape[3],
    2782           0 :                                                                       pol, itsImageShape[2], 
    2783           0 :                                                                       *imagepbcor(term) );
    2784             : 
    2785             : 
    2786           0 :                 LatticeExprNode pbmax( max( *pbsubim ) );
    2787           0 :                 Float pbmaxval = pbmax.getFloat();
    2788             : 
    2789           0 :                 if( pbmaxval<=0.0 )
    2790             :                   {
    2791           0 :                     os << LogIO::WARN << "Skipping PBCOR for C:" << chan << " P:" << pol << " because pb max is zero " << LogIO::POST;
    2792           0 :                     pbcorsubim->set(0.0);
    2793             :                   }
    2794             :                 else
    2795             :                   {
    2796             : 
    2797           0 :                     LatticeExpr<Float> thepbcor( iif( *(pbsubim) > 0.0 , (*(restoredsubim))/(*(pbsubim)) , 0.0 ) );
    2798           0 :                     pbcorsubim->copyData( thepbcor );
    2799             : 
    2800           0 :                 }// if not zero
    2801           0 :               }//chan
    2802             :           }//pol
    2803             : 
    2804             :         // Copy over the PB mask.
    2805           0 :         if((imagepbcor(term)->getDefaultMask()=="") && hasPB())
    2806           0 :           {copyMask(pb(),imagepbcor(term));}
    2807             : 
    2808             :         // Set restoring beam info
    2809           0 :         ImageInfo iminf = image(term)->imageInfo();
    2810             :         //iminf.setBeams( itsRestoredBeams );
    2811           0 :         imagepbcor(term)->setImageInfo(iminf);
    2812             : 
    2813           0 :   }// end pbcor
    2814             : 
    2815           0 :   Matrix<Float> SIImageStore::getSumWt(ImageInterface<Float>& target)
    2816             :   {
    2817           0 :     Record miscinfo = target.miscInfo();
    2818             :     
    2819           0 :     Matrix<Float> sumwt;
    2820           0 :     sumwt.resize();
    2821           0 :     if( miscinfo.isDefined("sumwt") 
    2822           0 :         && (miscinfo.dataType("sumwt")==TpArrayFloat || miscinfo.dataType("sumwt")==TpArrayDouble  )  ) 
    2823           0 :       { miscinfo.get( "sumwt" , sumwt ); } 
    2824           0 :     else   { sumwt.resize( IPosition(2, target.shape()[2], target.shape()[3] ) ); sumwt = 1.0;  }
    2825             :     
    2826           0 :     return sumwt;
    2827           0 :   }
    2828             :   
    2829           0 :   void SIImageStore::setSumWt(ImageInterface<Float>& target, Matrix<Float>& sumwt)
    2830             :   {
    2831           0 :     Record miscinfo = target.miscInfo();
    2832           0 :     miscinfo.define("sumwt", sumwt);
    2833           0 :     LatticeLocker lock1(target, FileLocker::Write);
    2834           0 :     target.setMiscInfo( miscinfo );
    2835           0 :   }
    2836             :   
    2837             : 
    2838          23 :   Bool SIImageStore::getUseWeightImage(ImageInterface<Float>& target)
    2839             :   {
    2840          23 :     Record miscinfo = target.miscInfo();
    2841             :     Bool useweightimage;
    2842          23 :     if( miscinfo.isDefined("useweightimage") && miscinfo.dataType("useweightimage")==TpBool )
    2843          23 :       { miscinfo.get( "useweightimage", useweightimage );  }
    2844           0 :     else { useweightimage = False; }
    2845             : 
    2846          23 :     return useweightimage;
    2847          23 :   }
    2848             :   /*
    2849             :   Bool SIImageStore::getUseWeightImage()
    2850             :   {
    2851             :     if( ! itsParentSumWt )
    2852             :       return False;
    2853             :     else 
    2854             :      return  getUseWeightImage( *itsParentSumWt );
    2855             :   }
    2856             :   */
    2857         156 :   void SIImageStore::setUseWeightImage(ImageInterface<Float>& target, Bool useweightimage)
    2858             :   {
    2859         156 :     Record miscinfo = target.miscInfo();
    2860         156 :     miscinfo.define("useweightimage", useweightimage);
    2861         156 :     LatticeLocker lock1(target, FileLocker::Write);
    2862         156 :     target.setMiscInfo( miscinfo );
    2863         156 :   }
    2864             :   
    2865             : 
    2866             : 
    2867          20 :   Bool SIImageStore::divideImageByWeightVal( ImageInterface<Float>& target )
    2868             :   {
    2869             : 
    2870          20 :     Array<Float> lsumwt;
    2871          20 :     sumwt()->get( lsumwt , False ); // For MT, this will always pick the zeroth sumwt, which it should.
    2872          20 :     LatticeLocker lock2(target, FileLocker::Write);
    2873             :     
    2874          20 :     IPosition imshape = target.shape();
    2875             : 
    2876             :     //cerr << " SumWt  : " << lsumwt << " sumwtshape : " << lsumwt.shape() << " image shape : " << imshape << endl;
    2877             : 
    2878          20 :     AlwaysAssert( lsumwt.shape()[2] == imshape[2] , AipsError ); // polplanes
    2879          20 :     AlwaysAssert( lsumwt.shape()[3] == imshape[3] , AipsError ); // chanplanes
    2880             : 
    2881          20 :     Bool div=False; // flag to signal if division actually happened, or weights are all 1.0
    2882             : 
    2883          40 :     for(Int pol=0; pol<lsumwt.shape()[2]; pol++)
    2884             :       {
    2885          64 :         for(Int chan=0; chan<lsumwt.shape()[3]; chan++)
    2886             :           {
    2887          44 :             IPosition pos(4,0,0,pol,chan);
    2888          44 :             if( lsumwt(pos) != 1.0 )
    2889             :               { 
    2890             :                 //              SubImage<Float>* subim=makePlane(  chan, True ,pol, True, target );
    2891             :                 std::shared_ptr<ImageInterface<Float> > subim=makeSubImage(0,1, 
    2892          44 :                                                                       chan, lsumwt.shape()[3],
    2893          44 :                                                                       pol, lsumwt.shape()[2], 
    2894          88 :                                                                       target );
    2895          44 :                 if ( lsumwt(pos) > 1e-07 ) {
    2896          52 :                     LatticeExpr<Float> le( (*subim)/lsumwt(pos) );
    2897          26 :                     subim->copyData( le );
    2898          26 :                   }
    2899             :                 else  {
    2900          18 :                     subim->set(0.0);
    2901             :                   }
    2902          44 :                 div=True;
    2903          44 :               }
    2904          44 :           }
    2905             :       }
    2906             : 
    2907             :     //    if( div==True ) cout << "Div image by sumwt : " << lsumwt << endl;
    2908             :     //    else cout << "Already normalized" << endl;
    2909             : 
    2910             :     //    lsumwt = 1.0; setSumWt( target , lsumwt );
    2911             : 
    2912          20 :     return div;
    2913          20 :   }
    2914             : 
    2915           9 :   void  SIImageStore::normPSF(Int term)
    2916             :   {
    2917             : 
    2918          18 :     for(Int pol=0; pol<itsImageShape[2]; pol++)
    2919             :       {
    2920          27 :         for(Int chan=0; chan<itsImageShape[3]; chan++)
    2921             :           {
    2922             :             ///     IPosition center(4,itsImageShape[0]/2,itsImageShape[1]/2,pol,chan);
    2923             :             
    2924             :             std::shared_ptr<ImageInterface<Float> > subim=makeSubImage(0,1, 
    2925          36 :                                                                   chan, itsImageShape[3],
    2926          18 :                                                                   pol, itsImageShape[2], 
    2927          36 :                                                                   (*psf(term)) );
    2928             : 
    2929             :             std::shared_ptr<ImageInterface<Float> > subim0=makeSubImage(0,1, 
    2930          36 :                                                                   chan, itsImageShape[3],
    2931          18 :                                                                   pol, itsImageShape[2], 
    2932          36 :                                                                   (*psf(0)) );
    2933             : 
    2934          18 :             LatticeLocker lock1(*(subim), FileLocker::Write);
    2935             : 
    2936          18 :             LatticeExprNode themax( max(*(subim0)) );
    2937          18 :             Float maxim = themax.getFloat();
    2938             :             
    2939          18 :             if ( maxim > 1e-07 )
    2940             :               {
    2941          24 :                 LatticeExpr<Float> normed( (*(subim)) / maxim );
    2942          12 :                 subim->copyData( normed );
    2943          12 :               }
    2944             :             else
    2945             :               {
    2946           6 :                 subim->set(0.0);
    2947             :               }
    2948          18 :           }//chan
    2949             :       }//pol
    2950             : 
    2951           9 :   }
    2952             : 
    2953           6 :   void SIImageStore::calcSensitivity()
    2954             :   {
    2955          12 :     LogIO os( LogOrigin("SIImageStore","calcSensitivity",WHERE) );
    2956             : 
    2957           6 :     Array<Float> lsumwt;
    2958           6 :     sumwt()->get( lsumwt , False ); // For MT, this will always pick the zeroth sumwt, which it should.
    2959             : 
    2960           6 :     IPosition shp( lsumwt.shape() );
    2961             :     //cout << "Sumwt shape : " << shp << " : " << lsumwt << endl;
    2962             :     //AlwaysAssert( shp.nelements()==4 , AipsError );
    2963             :     
    2964           6 :     os << "[" << itsImageName << "] Theoretical sensitivity (Jy/bm):" ;
    2965             :     
    2966           6 :     IPosition it(4,0,0,0,0);
    2967          12 :     for ( it[0]=0; it[0]<shp[0]; it[0]++)
    2968          12 :       for ( it[1]=0; it[1]<shp[1]; it[1]++)
    2969          12 :         for ( it[2]=0; it[2]<shp[2]; it[2]++)
    2970          21 :           for ( it[3]=0; it[3]<shp[3]; it[3]++)
    2971             :             {
    2972          15 :               if( shp[0]>1 ){os << "f"<< it[0]+(it[1]*shp[0]) << ":" ;}
    2973          15 :               if( shp[3]>1 ) { os << "c"<< it[3] << ":"; }
    2974          15 :               if( shp[2]>1 ) { os << "p"<< it[2]<< ":" ; }
    2975          15 :               if( lsumwt( it )  > 1e-07 ) 
    2976             :                 { 
    2977           9 :                   os << 1.0/(sqrt(lsumwt(it))) << " " ;
    2978             :                 }
    2979             :               else
    2980             :                 {
    2981           6 :                   os << "none" << " ";
    2982             :                 }
    2983             :             }
    2984             :     
    2985           6 :     os << LogIO::POST;
    2986             : 
    2987             :     //    Array<Float> sens = 1.0/sqrtsumwt;
    2988             : 
    2989             : 
    2990           6 :   }
    2991             : 
    2992           0 :   Double SIImageStore::calcFractionalBandwidth()
    2993             :   {
    2994           0 :     throw(AipsError("calcFractionalBandwidth is not implemented for SIImageStore. Only SIImageStoreMultiTerm"));
    2995             :   }
    2996             : 
    2997             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    2998             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    2999             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3000             : ///////////////////   Utility Functions to gather statistics on the imagestore.
    3001             : 
    3002          53 : Float SIImageStore::getPeakResidual()
    3003             : {
    3004         106 :     LogIO os( LogOrigin("SIImageStore","getPeakResidual",WHERE) );
    3005          53 :     LatticeLocker lock2 (*(residual()), FileLocker::Read);
    3006         106 :     ArrayLattice<Bool> pixelmask(residual()->getMask());
    3007         106 :     LatticeExpr<Float> resd(iif(pixelmask,abs(*residual()),0));
    3008             :     //LatticeExprNode pres( max(abs( *residual() ) ));
    3009          53 :     LatticeExprNode pres( max(resd) );
    3010          53 :     Float maxresidual = pres.getFloat();
    3011             :     
    3012          53 :     return maxresidual;
    3013          53 :   }
    3014             :   
    3015          38 : Float SIImageStore::getPeakResidualWithinMask()
    3016             :   {
    3017          76 :     LogIO os( LogOrigin("SIImageStore","getPeakResidualWithinMask",WHERE) );
    3018             :     //Float minresmask, maxresmask, minres, maxres;
    3019             :     //findMinMax( residual()->get(), mask()->get(), minres, maxres, minresmask, maxresmask );
    3020             : 
    3021          76 :     ArrayLattice<Bool> pixelmask(residual()->getMask());
    3022             :     //findMinMaxLattice(*residual(), *mask() , pixelmask, maxres,maxresmask, minres, minresmask);
    3023          76 :     LatticeExpr<Float> resd(iif(((*mask()) > 0) && pixelmask ,abs((*residual())),0));
    3024          38 :     LatticeExprNode pres( max(resd) );
    3025          38 :     Float maxresidual = pres.getFloat();
    3026             :     //Float maxresidual=max( abs(maxresmask), abs(minresmask) );
    3027          38 :     return maxresidual;
    3028          38 :   }
    3029             : 
    3030             :   // Calculate the total model flux
    3031          34 : Float SIImageStore::getModelFlux(uInt term)
    3032             :   {
    3033             :     //    LogIO os( LogOrigin("SIImageStore","getModelFlux",WHERE) );
    3034          34 :     LatticeLocker lock2 (*(model(term)), FileLocker::Read);
    3035          68 :     LatticeExprNode mflux( sum( *model(term) ) );
    3036          34 :     Float modelflux = mflux.getFloat();
    3037             :     //    Float modelflux = sum( model(term)->get() );
    3038             : 
    3039          34 :     return modelflux;
    3040          34 :   }
    3041             : 
    3042             :   // Check for non-zero model (this is different from getting model flux, for derived SIIMMT)
    3043          19 : Bool SIImageStore::isModelEmpty()
    3044             :   {
    3045          19 :     if( !itsModel && (! hasModel()) ) return True;
    3046          13 :     else return  ( fabs( getModelFlux(0) ) < 1e-08 );
    3047             :   }
    3048             : 
    3049             : 
    3050           7 : void SIImageStore::setPSFSidelobeLevel(const Float level){
    3051             : 
    3052           7 :   itsPSFSideLobeLevel=level;
    3053           7 : }
    3054             :   // Calculate the PSF sidelobe level...
    3055          59 :   Float SIImageStore::getPSFSidelobeLevel()
    3056             :   {
    3057         118 :     LogIO os( LogOrigin("SIImageStore","getPSFSidelobeLevel",WHERE) );
    3058             :     //cerr << "*****PSF sidelobe "<< itsPSFSideLobeLevel << endl;
    3059             :     /// Calculate only once, store and return for all subsequent calls.
    3060          59 :     if( itsPSFSideLobeLevel == 0.0 )
    3061             :       {
    3062             : 
    3063           5 :         ImageBeamSet thebeams = getBeamSet();
    3064           5 :         LatticeLocker lock2 (*(psf()), FileLocker::Read);
    3065             :         
    3066             :         //------------------------------------------------------------
    3067           5 :         IPosition oneplaneshape( itsImageShape );
    3068           5 :         AlwaysAssert( oneplaneshape.nelements()==4, AipsError );
    3069           5 :         oneplaneshape[2]=1; oneplaneshape[3]=1;
    3070           5 :         TempImage<Float> psfbeam( oneplaneshape, itsCoordSys );
    3071             :         
    3072             :         // In a loop through channels, subtract out or mask out the main lobe
    3073           5 :         Float allmin=0.0, allmax=0.0;
    3074          10 :         for(Int pol=0; pol<itsImageShape[2]; pol++)
    3075             :           {
    3076          15 :             for(Int chan=0; chan<itsImageShape[3]; chan++)
    3077             :               {
    3078             :                 std::shared_ptr<ImageInterface<Float> > onepsf=makeSubImage(0,1, 
    3079          20 :                                                                        chan, itsImageShape[3],
    3080          10 :                                                                        pol, itsImageShape[2], 
    3081          20 :                                                                        (*psf()) );
    3082             :                 
    3083             :                 
    3084          10 :                 GaussianBeam beam = thebeams.getBeam( chan, pol );
    3085          10 :                 Vector<Float> abeam(3); // Holds bmaj, bmin, pa  in asec, asec, deg 
    3086          10 :                 abeam[0] = beam.getMajor().get("arcsec").getValue() * C::arcsec;
    3087          10 :                 abeam[1] = beam.getMinor().get("arcsec").getValue() * C::arcsec;
    3088          10 :                 abeam[2] = (beam.getPA().get("deg").getValue() + 90.0)* C::degree;
    3089             : 
    3090             :                 //cout << "Beam : " << abeam << endl;
    3091             : 
    3092          10 :                 StokesImageUtil::MakeGaussianPSF( psfbeam,  abeam, False);
    3093             : 
    3094             :                 //              storeImg( String("psfbeam.im"), psfbeam );
    3095             :         
    3096             :                 //Subtract from PSF plane
    3097          20 :                 LatticeExpr<Float> delobed(  (*onepsf) - psfbeam  );
    3098             :                 
    3099             :                 // For debugging
    3100             :                 //onepsf->copyData( delobed );
    3101             :                 
    3102             :                 //Calc max and min and accumulate across channels. 
    3103             :                 
    3104          10 :                 LatticeExprNode minval_le( min( *onepsf ) );
    3105          10 :                 LatticeExprNode maxval_le( max( delobed ) );
    3106             : 
    3107          10 :                 Float minval = minval_le.getFloat();
    3108          10 :                 Float maxval = maxval_le.getFloat();
    3109             : 
    3110          10 :                 if( minval < allmin ) allmin = minval;
    3111          10 :                 if( maxval > allmax ) allmax = maxval;
    3112             : 
    3113             :                 //cout << "Chan : " << chan << "   minval : " << minval << "  maxval : " << maxval << endl;
    3114             :                 
    3115          10 :               }//chan
    3116             :           }//pol
    3117             :         
    3118             :         //------------------------------------------------------------
    3119             : 
    3120           5 :         itsPSFSideLobeLevel = max( fabs(allmin), fabs(allmax) );
    3121             : 
    3122             :         //os << "PSF min : " << allmin << " max : " << allmax << " psfsidelobelevel : " << itsPSFSideLobeLevel << LogIO::POST;
    3123             : 
    3124           5 :       }// if changed.
    3125             :     
    3126             :     //    LatticeExprNode psfside( min( *psf() ) );
    3127             :     //    itsPSFSideLobeLevel = fabs( psfside.getFloat() );
    3128             : 
    3129             :     //cout << "PSF sidelobe level : " << itsPSFSideLobeLevel << endl;
    3130          59 :     return itsPSFSideLobeLevel;
    3131          59 :   }
    3132             : 
    3133           0 :   void SIImageStore::findMinMax(const Array<Float>& lattice,
    3134             :                                         const Array<Float>& mask,
    3135             :                                         Float& minVal, Float& maxVal,
    3136             :                                         Float& minValMask, Float& maxValMask)
    3137             :   {
    3138           0 :     IPosition posmin(lattice.shape().nelements(), 0);
    3139           0 :     IPosition posmax(lattice.shape().nelements(), 0);
    3140             : 
    3141           0 :     if( sum(mask) <1e-06 ) {minValMask=0.0; maxValMask=0.0;}
    3142           0 :     else { minMaxMasked(minValMask, maxValMask, posmin, posmax, lattice,mask); }
    3143             : 
    3144           0 :     minMax( minVal, maxVal, posmin, posmax, lattice );
    3145           0 :   }
    3146             : 
    3147           0 : Array<Double> SIImageStore::calcRobustRMS(Array<Double>& mdns, const Float pbmasklevel, const Bool fastcalc)
    3148             : {    
    3149           0 :   LogIO os( LogOrigin("SIImageStore","calcRobustRMS",WHERE) );
    3150           0 :   Record*  regionPtr=0;
    3151           0 :   String LELmask("");
    3152           0 :   LatticeLocker lockres (*(residual()), FileLocker::Read);
    3153           0 :   ArrayLattice<Bool> pbmasklat(residual()->shape());
    3154           0 :   pbmasklat.set(False);
    3155           0 :   LatticeExpr<Bool> pbmask(pbmasklat);
    3156           0 :   if (hasPB()) {
    3157             :     // set bool mask: False = masked
    3158           0 :     pbmask = LatticeExpr<Bool> (iif(*pb() > pbmasklevel, True, False));
    3159           0 :     os << LogIO::DEBUG1 << "pbmask to be attached===> nfalse(pbmask.getMask())="<<nfalse(pbmask.getMask())<<endl; 
    3160             :   }
    3161             :   
    3162             :    
    3163           0 :   Record thestats;
    3164           0 :   if (fastcalc) { // older calculation 
    3165             :     // need to apply pbmask if present to be consistent between fastcalc = true and false.
    3166             :     //TempImage<Float>* tempRes = new TempImage<Float>(residual()->shape(), residual()->coordinates(), SDMaskHandler::memoryToUse());
    3167           0 :     auto tempRes = std::shared_ptr<TempImage<Float>>(new TempImage<Float>(residual()->shape(), residual()->coordinates(), SDMaskHandler::memoryToUse()));
    3168           0 :     tempRes->copyData(*residual());
    3169           0 :     tempRes->attachMask(pbmask);
    3170             :     //thestats = SDMaskHandler::calcImageStatistics(*residual(), LELmask, regionPtr, True);
    3171           0 :     thestats = SDMaskHandler::calcImageStatistics(*tempRes, LELmask, regionPtr, True);
    3172           0 :   }
    3173             :   else { // older way to calculate 
    3174             :     // use the new statistic calculation algorithm
    3175           0 :     Vector<Bool> dummyvec;
    3176             :     // TT: 2018.08.01 using revised version (the older version of this is renameed to calcRobustImageStatisticsOld)
    3177           0 :     thestats = SDMaskHandler::calcRobustImageStatistics(*residual(), *mask(), pbmask,  LELmask, regionPtr, True, dummyvec);
    3178           0 :   }
    3179             :     
    3180             : 
    3181             :   /***
    3182             :   ImageStatsCalculator imcalc( residual(), regionPtr, LELmask, False); 
    3183             : 
    3184             :   Vector<Int> axes(2);
    3185             :   axes[0] = 0;
    3186             :   axes[1] = 1;
    3187             :   imcalc.setAxes(axes);
    3188             :   imcalc.setRobust(True);
    3189             :   Record thestats = imcalc.statistics();
    3190             :   //cout<<"thestats="<<thestats<<endl;
    3191             :   ***/
    3192             : 
    3193             :   //Array<Double>rmss, mads, mdns;
    3194           0 :   Array<Double>rmss, mads;
    3195             :   //thestats.get(RecordFieldId("max"), maxs);
    3196           0 :   thestats.get(RecordFieldId("rms"), rmss);
    3197           0 :   thestats.get(RecordFieldId("medabsdevmed"), mads);
    3198           0 :   thestats.get(RecordFieldId("median"), mdns);
    3199             :   
    3200             :   //os << LogIO::DEBUG1 << "Max : " << maxs << LogIO::POST;
    3201           0 :   os << LogIO::DEBUG1 << "RMS : " << rmss << LogIO::POST;
    3202           0 :   os << LogIO::DEBUG1 << "MAD : " << mads << LogIO::POST;
    3203             :   
    3204             :   // this for the new noise calc
    3205             :   //return mdns+mads*1.4826;
    3206             :   // this is the old noise calc
    3207           0 :   return mads*1.4826;
    3208           0 : }
    3209             : 
    3210           0 :   void SIImageStore::printImageStats()
    3211             :   {
    3212           0 :     LogIO os( LogOrigin("SIImageStore","printImageStats",WHERE) );
    3213           0 :     Float minresmask=0, maxresmask=0, minres=0, maxres=0;
    3214             :     //    findMinMax( residual()->get(), mask()->get(), minres, maxres, minresmask, maxresmask );
    3215           0 :     LatticeLocker lock1 (*(residual()), FileLocker::Read);
    3216           0 :     ArrayLattice<Bool> pixelmask(residual()->getMask());
    3217           0 :     if(hasMask())
    3218             :       {
    3219           0 :         LatticeLocker lock2 (*(mask()), FileLocker::Read);
    3220           0 :         findMinMaxLattice(*residual(), *mask() , pixelmask, maxres,maxresmask, minres, minresmask);
    3221           0 :       }
    3222             :     else
    3223             :       {
    3224             :         //LatticeExprNode pres( max( *residual() ) );
    3225           0 :         LatticeExprNode pres( max( iif(pixelmask,*residual(),0) ) );
    3226           0 :         maxres = pres.getFloat();
    3227             :         //LatticeExprNode pres2( min( *residual() ) );
    3228           0 :         LatticeExprNode pres2( min( iif(pixelmask,*residual(),0) ) );
    3229           0 :         minres = pres2.getFloat();
    3230           0 :       }
    3231             : 
    3232           0 :     os << "[" << itsImageName << "]" ;
    3233           0 :     os << " Peak residual (max,min) " ;
    3234           0 :     if( minresmask!=0.0 || maxresmask!=0.0 )
    3235           0 :       { os << "within mask : (" << maxresmask << "," << minresmask << ") "; }
    3236           0 :     os << "over full image : (" << maxres << "," << minres << ")" << LogIO::POST;
    3237             : 
    3238           0 :     os << "[" << itsImageName << "] Total Model Flux : " << getModelFlux() << LogIO::POST; 
    3239             : 
    3240             :     
    3241           0 :     Record*  regionPtr=0;
    3242           0 :     String LELmask("");
    3243           0 :     Record thestats = SDMaskHandler::calcImageStatistics(*residual(), LELmask, regionPtr, True);
    3244           0 :     Array<Double> maxs, mins;
    3245           0 :     thestats.get(RecordFieldId("max"), maxs);
    3246           0 :     thestats.get(RecordFieldId("min"), mins);
    3247             :     //os << LogIO::DEBUG1 << "Max : " << maxs << LogIO::POST;
    3248             :     //os << LogIO::DEBUG1 << "Min : " << mins << LogIO::POST;
    3249             :     
    3250           0 :   }
    3251             : 
    3252             :   // Calculate the total model flux
    3253          43 :   Float SIImageStore::getMaskSum()
    3254             :   {
    3255          86 :     LogIO os( LogOrigin("SIImageStore","getMaskSum",WHERE) );
    3256          43 :     LatticeLocker lock2 (*(mask()), FileLocker::Read);
    3257          86 :     LatticeExprNode msum( sum( *mask() ) );
    3258          43 :     Float masksum = msum.getFloat();
    3259             : 
    3260             :     //    Float masksum = sum( mask()->get() );
    3261             : 
    3262          43 :     return masksum;
    3263          43 :   }
    3264             : 
    3265           0 : Bool SIImageStore::findMinMaxLattice(const Lattice<Float>& lattice, 
    3266             :                                      const Lattice<Float>& mask,
    3267             :                                      const Lattice<Bool>& pixelmask,
    3268             :                                      Float& maxAbs, Float& maxAbsMask, 
    3269             :                                      Float& minAbs, Float& minAbsMask )
    3270             : {
    3271             : 
    3272             :   //FOR DEGUG
    3273             :   //LogIO os( LogOrigin("SIImageStore","findMinMaxLattice",WHERE) );
    3274             : 
    3275           0 :   maxAbs=0.0;maxAbsMask=0.0;
    3276           0 :   minAbs=1e+10;minAbsMask=1e+10;
    3277           0 :   LatticeLocker lock1 (const_cast<Lattice<Float>& > (lattice), FileLocker::Read);
    3278           0 :   LatticeLocker lock2 (const_cast<Lattice<Float>& >(mask), FileLocker::Read);
    3279           0 :   LatticeLocker lock3 (const_cast<Lattice<Bool>& >(pixelmask), FileLocker::Read);
    3280           0 :   const IPosition tileShape = lattice.niceCursorShape();
    3281           0 :   TiledLineStepper ls(lattice.shape(), tileShape, 0);
    3282             :   {
    3283           0 :     RO_LatticeIterator<Float> li(lattice, ls);
    3284           0 :     RO_LatticeIterator<Float> mi(mask, ls);
    3285           0 :     RO_LatticeIterator<Bool> pmi(pixelmask, ls);
    3286           0 :     for(li.reset(),mi.reset(),pmi.reset();!li.atEnd();li++, mi++, pmi++) {
    3287           0 :       IPosition posMax=li.position();
    3288           0 :       IPosition posMin=li.position();
    3289           0 :       IPosition posMaxMask=li.position();
    3290           0 :       IPosition posMinMask=li.position();
    3291           0 :       Float maxVal=0.0;
    3292           0 :       Float minVal=0.0;
    3293           0 :       Float maxValMask=0.0;
    3294           0 :       Float minValMask=0.0;
    3295             : 
    3296             : 
    3297             :       // skip if lattice chunk is masked entirely.
    3298           0 :       if(ntrue(pmi.cursor()) > 0 ) {
    3299           0 :         const MaskedArray<Float> marr(li.cursor(), pmi.cursor());
    3300           0 :         const MaskedArray<Float> marrinmask(li.cursor() * mi.cursor(), pmi.cursor());
    3301             :       //minMax( minVal, maxVal, posMin, posMax, li.cursor() );
    3302           0 :       minMax( minVal, maxVal, posMin, posMax, marr );
    3303             :       //minMaxMasked(minValMask, maxValMask, posMin, posMax, li.cursor(), mi.cursor());
    3304           0 :       minMax(minValMask, maxValMask, posMin, posMax, marrinmask);
    3305             :       
    3306             :       //os<<"DONE minMax"<<LogIO::POST; 
    3307           0 :       if( (maxVal) > (maxAbs) ) maxAbs = maxVal;
    3308           0 :       if( (maxValMask) > (maxAbsMask) ) maxAbsMask = maxValMask;
    3309             : 
    3310           0 :       if( (minVal) < (minAbs) ) minAbs = minVal;
    3311           0 :       if( (minValMask) < (minAbsMask) ) minAbsMask = minValMask;
    3312           0 :       }
    3313             : 
    3314           0 :     }
    3315           0 :   }
    3316             : 
    3317           0 :   return True;
    3318             : 
    3319             : 
    3320           0 : }
    3321             : 
    3322             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3323             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3324             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3325             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3326             : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    3327             : 
    3328             :   //
    3329             :   //-------------------------------------------------------------
    3330             :   // Initialize the internals of the object.  Perhaps other such
    3331             :   // initializations in the constructors can be moved here too.
    3332             :   //
    3333         109 :   void SIImageStore::init()
    3334             :   {
    3335         109 :     imageExts.resize(MAX_IMAGE_IDS);
    3336             : 
    3337         109 :     imageExts(MASK) = ".mask";
    3338         109 :     imageExts(PSF) = ".psf";
    3339         109 :     imageExts(MODEL) = ".model";
    3340         109 :     if (not itsIsSingleDishStore) {
    3341          88 :       imageExts(RESIDUAL) = ".residual";
    3342          88 :       imageExts(IMAGE) = ".image";
    3343             :     }
    3344             :     else {
    3345             :       // The initial residual image IS the single-dish image
    3346          21 :       imageExts(RESIDUAL) = ".image";
    3347             :       // Make sure we have no duplicates in the vector
    3348             :       // Not sure what should be done here
    3349          21 :       imageExts(IMAGE) = ".wrongly-deconvolved-single-dish-image";
    3350             :     }
    3351         109 :     imageExts(WEIGHT) = ".weight";
    3352         109 :     imageExts(SUMWT) = ".sumwt";
    3353         109 :     imageExts(GRIDWT) = ".gridwt";
    3354         109 :     imageExts(PB) = ".pb";
    3355         109 :     imageExts(FORWARDGRID) = ".forward";
    3356         109 :     imageExts(BACKWARDGRID) = ".backward";
    3357         109 :     imageExts(IMAGEPBCOR) = ".image.pbcor";
    3358             : 
    3359         109 :     itsParentPsf = itsPsf;
    3360         109 :     itsParentModel = itsModel;
    3361         109 :     itsParentResidual = itsResidual;
    3362         109 :     itsParentWeight = itsWeight;
    3363         109 :     itsParentImage = itsImage;
    3364         109 :     itsParentSumWt = itsSumWt;
    3365         109 :     itsParentMask = itsMask;
    3366         109 :     itsParentImagePBcor = itsImagePBcor;
    3367             : 
    3368             :     // cout << "parent shape : " << itsParentImageShape
    3369             :     //   << "   shape : " << itsImageShape << endl;
    3370         109 :     itsParentImageShape = itsImageShape;
    3371         109 :     itsParentCoordSys = itsCoordSys;
    3372             : 
    3373         109 :     if ( itsNFacets>1 or itsNChanChunks>1 or itsNPolChunks>1 ) {
    3374           0 :       itsImageShape = IPosition(4,0,0,0,0);
    3375             :     }
    3376             : 
    3377         109 :     itsOpened = 0;
    3378             : 
    3379         109 :     itsPSFSideLobeLevel = 0.0;
    3380         109 :     itsReadLock = nullptr;
    3381         109 :     itsDataPolRep = StokesImageUtil::UNKNOWN; // Should throw an exception if
    3382             :                                               // it is not initialized properly
    3383         109 :   }
    3384             : 
    3385             : 
    3386           0 : void SIImageStore::regridToModelImage( ImageInterface<Float> &inputimage, Int term )
    3387             :   {
    3388             :     try 
    3389             :       {
    3390             : 
    3391             :     //output coords
    3392           0 :         IPosition outshape = itsImageShape;
    3393           0 :         CoordinateSystem outcsys = itsCoordSys;
    3394           0 :         DirectionCoordinate outDirCsys = outcsys.directionCoordinate();
    3395           0 :         SpectralCoordinate outSpecCsys = outcsys.spectralCoordinate();
    3396             :      
    3397             :         // do regrid   
    3398           0 :         IPosition axes(3,0, 1, 2);
    3399           0 :         IPosition inshape = inputimage.shape();
    3400           0 :         CoordinateSystem incsys = inputimage.coordinates(); 
    3401           0 :         DirectionCoordinate inDirCsys = incsys.directionCoordinate();
    3402           0 :         SpectralCoordinate inSpecCsys = incsys.spectralCoordinate();
    3403             : 
    3404           0 :         Vector<Int> dirAxes = CoordinateUtil::findDirectionAxes(incsys);
    3405           0 :         axes(0) = dirAxes(0); 
    3406           0 :         axes(1) = dirAxes(1);
    3407           0 :         axes(2) = CoordinateUtil::findSpectralAxis(incsys);
    3408             :         
    3409             :         try {
    3410           0 :           ImageRegrid<Float> imregrid;
    3411           0 :           imregrid.regrid( *(model(term)), Interpolate2D::LINEAR, axes, inputimage ); 
    3412           0 :         } catch (AipsError &x) {
    3413           0 :           throw(AipsError("ImageRegrid error : "+ x.getMesg()));
    3414           0 :         }
    3415             :         
    3416           0 :       }catch(AipsError &x)
    3417             :       {
    3418           0 :         throw(AipsError("Error in regridding input model image to target coordsys : " + x.getMesg()));
    3419           0 :       }
    3420           0 :   }
    3421             : 
    3422             :   //
    3423             :   //---------------------------------------------------------------
    3424             :   //
    3425           0 :   void SIImageStore::makePersistent(String& fileName)
    3426             :   {
    3427           0 :     LogIO logIO(LogOrigin("SIImageStore", "makePersistent"));
    3428           0 :     ofstream outFile; outFile.open(fileName.c_str(),std::ofstream::out);
    3429           0 :     if (!outFile) logIO << "Failed to open filed \"" << fileName << "\"" << LogIO::EXCEPTION;
    3430             :     //  String itsImageName;
    3431           0 :     outFile << "itsImageNameBase: " << itsImageName << endl;
    3432             : 
    3433             :     //IPosition itsImageShape;
    3434           0 :     outFile << "itsImageShape: " << itsImageShape.nelements() << " ";
    3435           0 :     for (uInt i=0;i<itsImageShape.nelements(); i++) outFile << itsImageShape(i) << " "; outFile << endl;
    3436             : 
    3437             :     // Don't know what to do with this.  Looks like this gets
    3438             :     // filled-in from one of the images.  So load this from one of the
    3439             :     // images if they exist?
    3440             :     //CoordinateSystem itsCoordSys; 
    3441             : 
    3442             :     // Int itsNFacets;
    3443           0 :     outFile << "itsNFacets: " << itsNFacets << endl;
    3444           0 :     outFile << "itsUseWeight: " << itsUseWeight << endl;
    3445             :     
    3446             : 
    3447             :     // Misc Information to go into the header. 
    3448             :     //    Record itsMiscInfo; 
    3449           0 :     itsMiscInfo.print(outFile);
    3450             :     
    3451             :     // std::shared_ptr<ImageInterface<Float> > itsMask, itsPsf, itsModel, itsResidual, itsWeight, itsImage, itsSumWt;
    3452             :     // std::shared_ptr<ImageInterface<Complex> > itsForwardGrid, itsBackwardGrid;
    3453             : 
    3454           0 :     Vector<Bool> ImageExists(MAX_IMAGE_IDS);
    3455           0 :     if ( ! itsMask )     ImageExists(MASK)=False;
    3456           0 :     if ( ! itsPsf )      ImageExists(PSF)=False;
    3457           0 :     if ( ! itsModel )    ImageExists(MODEL)=False;
    3458           0 :     if ( ! itsResidual ) ImageExists(RESIDUAL)=False;
    3459           0 :     if ( ! itsWeight )   ImageExists(WEIGHT)=False;
    3460           0 :     if ( ! itsImage )    ImageExists(IMAGE)=False;
    3461           0 :     if ( ! itsSumWt )    ImageExists(SUMWT)=False;
    3462           0 :     if ( ! itsGridWt )   ImageExists(GRIDWT)=False;
    3463           0 :     if ( ! itsPB )       ImageExists(PB)=False;
    3464             : 
    3465           0 :     if ( ! itsForwardGrid )    ImageExists(FORWARDGRID)=False;
    3466           0 :     if ( ! itsBackwardGrid )   ImageExists(BACKWARDGRID)=False;
    3467             :     
    3468           0 :     outFile << "ImagesExist: " << ImageExists << endl;
    3469           0 :   }
    3470             :   //
    3471             :   //---------------------------------------------------------------
    3472             :   //
    3473           0 :   void SIImageStore::recreate(String& fileName)
    3474             :   {
    3475           0 :     LogIO logIO(LogOrigin("SIImageStore", "recreate"));
    3476           0 :     ifstream inFile; inFile.open(fileName.c_str(),std::ofstream::out);
    3477           0 :     if (!inFile) logIO << "Failed to open filed \"" << fileName << "\"" << LogIO::EXCEPTION;
    3478             : 
    3479           0 :     String token;
    3480           0 :     inFile >> token; if (token == "itsImageNameBase:") inFile >> itsImageName;
    3481             : 
    3482           0 :     inFile >> token; 
    3483           0 :     if (token=="itsImageShape:")
    3484             :       {
    3485             :         Int n;
    3486           0 :         inFile >> n;
    3487           0 :         itsImageShape.resize(n);
    3488           0 :         for (Int i=0;i<n; i++) inFile >> itsImageShape(i);
    3489             :       }
    3490             : 
    3491             :     // Int itsNFacets;
    3492           0 :     inFile >> token; if (token=="itsNFacets:") inFile >> itsNFacets;
    3493           0 :     inFile >> token; if (token=="itsUseWeight:") inFile >> itsUseWeight;
    3494             : 
    3495           0 :     Bool coordSysLoaded=False;
    3496           0 :     String itsName;      
    3497             :     try 
    3498             :       {
    3499           0 :         itsName=itsImageName+imageExts(MASK);casa::openImage(itsName,     itsMask);
    3500           0 :         if (coordSysLoaded==False) {itsCoordSys=itsMask->coordinates(); itsMiscInfo=itsImage->miscInfo();coordSysLoaded=True;}
    3501           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3502             :     try 
    3503             :       {
    3504           0 :         itsName=itsImageName+imageExts(MODEL);casa::openImage(itsName,    itsModel);
    3505           0 :         if (coordSysLoaded==False) {itsCoordSys=itsModel->coordinates(); itsMiscInfo=itsModel->miscInfo();coordSysLoaded=True;}
    3506           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3507             :     try 
    3508             :       {
    3509           0 :         itsName=itsImageName+imageExts(RESIDUAL);casa::openImage(itsName, itsResidual);
    3510           0 :         if (coordSysLoaded==False) {itsCoordSys=itsResidual->coordinates(); itsMiscInfo=itsResidual->miscInfo();coordSysLoaded=True;}
    3511           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3512             :     try 
    3513             :       {
    3514           0 :         itsName=itsImageName+imageExts(WEIGHT);casa::openImage(itsName,   itsWeight);
    3515           0 :         if (coordSysLoaded==False) {itsCoordSys=itsWeight->coordinates(); itsMiscInfo=itsWeight->miscInfo();coordSysLoaded=True;}
    3516           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3517             :     try 
    3518             :       {
    3519           0 :         itsName=itsImageName+imageExts(IMAGE);casa::openImage(itsName,    itsImage);
    3520           0 :         if (coordSysLoaded==False) {itsCoordSys=itsImage->coordinates(); itsMiscInfo=itsImage->miscInfo();coordSysLoaded=True;}
    3521           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3522             :     try 
    3523             :       {
    3524           0 :         itsName=itsImageName+imageExts(SUMWT);casa::openImage(itsName,    itsSumWt);
    3525           0 :         if (coordSysLoaded==False) {itsCoordSys=itsSumWt->coordinates(); itsMiscInfo=itsSumWt->miscInfo();coordSysLoaded=True;}
    3526           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3527             :     try
    3528             :       {
    3529           0 :         itsName=itsImageName+imageExts(PSF);casa::openImage(itsName,      itsPsf);
    3530           0 :         if (coordSysLoaded==False) {itsCoordSys=itsPsf->coordinates(); itsMiscInfo=itsPsf->miscInfo();coordSysLoaded=True;}
    3531           0 :       } catch (AipsIO& x) {logIO << "\"" << itsName << "\" not found." << LogIO::WARN;};
    3532             :     try
    3533             :       {
    3534           0 :         casa::openImage(itsImageName+imageExts(FORWARDGRID),  itsForwardGrid);
    3535           0 :         casa::openImage(itsImageName+imageExts(BACKWARDGRID), itsBackwardGrid);
    3536             :       }
    3537           0 :     catch (AipsError& x)
    3538             :       {
    3539           0 :         logIO << "Did not find forward and/or backward grid.  Just say'n..." << LogIO::POST;
    3540           0 :       }
    3541             : 
    3542           0 :   }
    3543             : //////////////
    3544           0 :   Bool SIImageStore::intersectComplexImage(const String& ComplexImageName){
    3545           0 :         Vector<Int> whichStokes(0);
    3546           0 :         CoordinateSystem cimageCoord = StokesImageUtil::CStokesCoord( itsCoordSys,
    3547           0 :                                                                   whichStokes, itsDataPolRep);
    3548             : 
    3549             : 
    3550             :         //cerr <<"itsDataPolRep " << itsDataPolRep << endl;
    3551             :         
    3552           0 :         CountedPtr<PagedImage<Complex> > compliantImage =nullptr;
    3553             :         {
    3554           0 :           PagedImage<Complex>inputImage(ComplexImageName);
    3555           0 :           IPosition theShape=itsImageShape;
    3556           0 :           theShape(0)=inputImage.shape()(0);
    3557           0 :           theShape(1)=inputImage.shape()(1);
    3558           0 :           CoordinateSystem inpcsys=inputImage.coordinates();
    3559           0 :           Vector<Double> refpix=cimageCoord.referencePixel();
    3560           0 :           refpix(0)+=(theShape(0)-itsImageShape(0))/2.0;
    3561           0 :           refpix(1)+=(theShape(1)-itsImageShape(1))/2.0;
    3562           0 :           cimageCoord.setReferencePixel(refpix);
    3563           0 :           String tmpImage=File::newUniqueName(".", "TempImage").absoluteName();
    3564           0 :           compliantImage=new PagedImage<Complex>(theShape, cimageCoord, tmpImage);
    3565           0 :           compliantImage->set(0.0);
    3566           0 :           IPosition iblc(theShape.nelements(),0);
    3567           0 :           IPosition itrc=theShape-1;
    3568             :           //cerr << "blc "  << iblc << " trc " << itrc  << " shape " << theShape << endl;
    3569           0 :           LCBox lbox(iblc, itrc, theShape);
    3570           0 :           ImageRegion imagreg(WCBox(lbox, cimageCoord));
    3571             :                 
    3572             :           
    3573           0 :           SubImage<Complex> subim(inputImage, imagreg, false);
    3574             :           //cerr << "shapes " << inputImage.shape() << "  sub " << subim.shape() << " compl " << compliantImage->shape() << endl;
    3575           0 :           compliantImage->copyData(subim);
    3576             :                         
    3577           0 :         }
    3578           0 :         TableUtil::deleteTable(ComplexImageName);
    3579           0 :         compliantImage->rename(ComplexImageName);
    3580           0 :         return True;
    3581             :                 
    3582           0 :   }
    3583             :         
    3584             : 
    3585             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
    3586             :   //////////////////////////////////////////////////////////////////////////////////////////////////////
    3587             : 
    3588             : } //# NAMESPACE CASA - END
    3589             : 

Generated by: LCOV version 1.16