LCOV - code coverage report
Current view: top level - synthesis/ImagerObjects - SynthesisDeconvolver.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 108 637 17.0 %
Date: 2025-08-21 08:01:32 Functions: 7 31 22.6 %

          Line data    Source code
       1             : //# SynthesisDeconvolver.cc: Implementation of Imager.h
       2             : //# Copyright (C) 1997-2020
       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             : 
      42             : #include <casacore/casa/OS/DirectoryIterator.h>
      43             : #include <casacore/casa/OS/File.h>
      44             : #include <casacore/casa/OS/Path.h>
      45             : 
      46             : #include <casacore/casa/OS/HostInfo.h>
      47             : 
      48             : #include <casacore/images/Images/TempImage.h>
      49             : #include <casacore/images/Images/SubImage.h>
      50             : #include <casacore/images/Regions/ImageRegion.h>
      51             : #include <casacore/lattices/Lattices/LatticeLocker.h>
      52             : #include <synthesis/ImagerObjects/CubeMinorCycleAlgorithm.h>
      53             : #include <imageanalysis/ImageAnalysis/CasaImageBeamSet.h>
      54             : #include <synthesis/ImagerObjects/SynthesisDeconvolver.h>
      55             : #include <synthesis/ImagerObjects/SIMinorCycleController.h>
      56             : 
      57             : #include <sys/types.h>
      58             : #include <unistd.h>
      59             : using namespace std;
      60             : 
      61             : using namespace casacore;
      62             : extern casa::Applicator casa::applicator;
      63             : namespace casa { //# NAMESPACE CASA - BEGIN
      64             : 
      65          17 :   SynthesisDeconvolver::SynthesisDeconvolver() :
      66          17 :                                        itsDeconvolver(nullptr),
      67          17 :                                        itsMaskHandler(nullptr ),
      68          17 :                itsImages(nullptr),
      69          17 :                itsImageName(""),
      70             :                                        //itsPartImageNames(Vector<String>(0)),
      71          17 :                                        itsBeam(0.0),
      72          17 :                                        itsDeconvolverId(0),
      73          17 :                                        itsScales(Vector<Float>()),
      74          17 :                itsMaskType(""),
      75          17 :                itsPBMask(0.0),
      76             :                                        //itsMaskString(String("")),
      77          17 :                itsIterDone(0.0),
      78          17 :                itsChanFlag(Vector<Bool>(0)),
      79          17 :                itsRobustStats(Record()),
      80          17 :                initializeChanMaskFlag(false),
      81          17 :                itsPosMask(nullptr),
      82          17 :                                        itsIsMaskLoaded(false),
      83          17 :                                        itsMaskSum(-1e+9),
      84          17 :                                        itsPreviousFutureRes(0.0),
      85          85 :                                        itsPreviousIterBotRec_p(Record())
      86             :   {
      87          17 :   }
      88             : 
      89          17 :   SynthesisDeconvolver::~SynthesisDeconvolver()
      90             :   {
      91          34 :         LogIO os( LogOrigin("SynthesisDeconvolver","descructor",WHERE) );
      92          17 :         os << LogIO::DEBUG1 << "SynthesisDeconvolver destroyed" << LogIO::POST;
      93          17 :         SynthesisUtilMethods::getResource("End SynthesisDeconvolver");
      94             : 
      95          17 :   }
      96             : 
      97          17 :   void SynthesisDeconvolver::setupDeconvolution(const SynthesisParamsDeconv& decpars)
      98             :   {
      99          34 :     LogIO os( LogOrigin("SynthesisDeconvolver","setupDeconvolution",WHERE) );
     100             : 
     101             :     //Copy this decpars into a private variable that can be used elsewhere
     102             :     //there is no proper copy operator (as public casa::Arrays members = operator fails)
     103          17 :     itsDecPars.fromRecord(decpars.toRecord());
     104          17 :     itsImageName = decpars.imageName;
     105          17 :     itsStartingModelNames = decpars.startModel;
     106          17 :     itsDeconvolverId = decpars.deconvolverId;
     107             : 
     108          17 :     os << "Set Deconvolution Options for [" << itsImageName << "] : " << decpars.algorithm ;
     109             : 
     110          17 :     if( itsStartingModelNames.nelements()>0 && itsStartingModelNames[0].length() > 0 )
     111           0 :       os << " , starting from model : " << itsStartingModelNames;
     112          17 :     os << LogIO::POST;
     113             : 
     114             :     try
     115             :       {
     116          17 :         if(decpars.algorithm==String("hogbom"))
     117             :           {
     118           0 :             itsDeconvolver.reset(new SDAlgorithmHogbomClean());
     119             :           }
     120          17 :         else if(decpars.algorithm==String("mtmfs"))
     121             :           {
     122           0 :             itsDeconvolver.reset(new SDAlgorithmMSMFS( decpars.nTaylorTerms, decpars.scales, decpars.scalebias ));
     123             :           }
     124          17 :         else if(decpars.algorithm==String("clark_exp"))
     125             :           {
     126           0 :             itsDeconvolver.reset(new SDAlgorithmClarkClean("clark"));
     127             :           }
     128          17 :         else if(decpars.algorithm==String("clarkstokes_exp"))
     129             :           {
     130           0 :             itsDeconvolver.reset(new SDAlgorithmClarkClean("clarkstokes"));
     131             :           }
     132          17 :         else if(decpars.algorithm==String("clark"))
     133             :           {
     134          17 :             itsDeconvolver.reset(new SDAlgorithmClarkClean2("clark"));
     135             :           }
     136           0 :         else if(decpars.algorithm==String("clarkstokes"))
     137             :           {
     138           0 :             itsDeconvolver.reset(new SDAlgorithmClarkClean2("clarkstokes"));
     139             :           }
     140           0 :         else if(decpars.algorithm==String("multiscale"))
     141             :           {
     142           0 :             itsDeconvolver.reset(new SDAlgorithmMSClean( decpars.scales, decpars.scalebias ));
     143             :           }
     144           0 :         else if(decpars.algorithm==String("mem"))
     145             :           {
     146           0 :             itsDeconvolver.reset(new SDAlgorithmMEM( "entropy" ));
     147             :           }
     148           0 :         else if (decpars.algorithm==String("asp"))
     149             :           {
     150             :             /*bool isSingle = false;
     151             :             if (decpars.specmode == String("mfs"))
     152             :               isSingle = true;
     153             :             */
     154             : 
     155             :             // CAS-13901 : When `deconvolve()` is called on a cube,
     156             :             // `decpars.specmode` defaults to MFS here, since there is no way to
     157             :             // specify specmode within deconvolve. Therefore `isSingle` is
     158             :             // forced to False always.  The side-effect of this is that
     159             :             // multi-plane MFS images will be slightly slowed down.
     160             : 
     161           0 :             bool isSingle = false;
     162           0 :             itsDeconvolver.reset(new SDAlgorithmAAspClean(decpars.fusedThreshold, isSingle, decpars.largestscale));
     163             :           }
     164             :         else
     165             :           {
     166           0 :             throw( AipsError("Un-known algorithm : "+decpars.algorithm) );
     167             :           }
     168             : 
     169             :         // Set restoring beam options
     170          17 :         itsDeconvolver->setRestoringBeam( decpars.restoringbeam, decpars.usebeam );
     171          17 :         itsUseBeam = decpars.usebeam;// store this info also here.
     172             : 
     173             :         // Set Masking options
     174             :         //      itsDeconvolver->setMaskOptions( decpars.maskType );
     175          17 :         itsMaskHandler.reset(new SDMaskHandler());
     176             :         //itsMaskString = decpars.maskString;
     177          17 :         itsMaskType = decpars.maskType;
     178          17 :         if(itsMaskType=="auto-thresh")
     179             :           {
     180           0 :             itsAutoMaskAlgorithm="thresh";
     181             :           }
     182          17 :         else if(itsMaskType=="auto-thresh2")
     183             :           {
     184           0 :             itsAutoMaskAlgorithm="thresh2";
     185             :           }
     186          17 :         else if(itsMaskType=="auto-multithresh")
     187             :           {
     188           0 :             itsAutoMaskAlgorithm="multithresh";
     189             :           }
     190          17 :         else if(itsMaskType=="auto-onebox")
     191             :           {
     192           0 :             itsAutoMaskAlgorithm="onebox";
     193             :           }
     194             :         else {
     195          17 :             itsAutoMaskAlgorithm="";
     196             :         }
     197          17 :         itsPBMask = decpars.pbMask;
     198          17 :         itsMaskString = decpars.maskString;
     199          51 :         if(decpars.maskList.nelements()==0 ||
     200          34 :             (decpars.maskList.nelements()==1 && decpars.maskList[0]==""))
     201             :           {
     202          17 :             itsMaskList.resize(1);
     203          17 :             itsMaskList[0] = itsMaskString;
     204             :           }
     205             :         else
     206             :           {
     207           0 :             itsMaskList = decpars.maskList;
     208             :           }
     209          17 :         itsMaskThreshold = decpars.maskThreshold;
     210          17 :         itsFracOfPeak = decpars.fracOfPeak;
     211          17 :         itsMaskResolution = decpars.maskResolution;
     212          17 :         itsMaskResByBeam = decpars.maskResByBeam;
     213          17 :         itsNMask = decpars.nMask;
     214             :         //itsAutoAdjust = decpars.autoAdjust;
     215             :         //desable autoadjust
     216          17 :         itsAutoAdjust = false;
     217          17 :         itsSidelobeThreshold = decpars.sidelobeThreshold;
     218          17 :         itsNoiseThreshold = decpars.noiseThreshold;
     219          17 :         itsLowNoiseThreshold = decpars.lowNoiseThreshold;
     220          17 :         itsNegativeThreshold = decpars.negativeThreshold;
     221          17 :         itsSmoothFactor = decpars.smoothFactor;
     222          17 :         itsMinBeamFrac = decpars.minBeamFrac;
     223          17 :         itsCutThreshold = decpars.cutThreshold;
     224          17 :         itsGrowIterations = decpars.growIterations;
     225          17 :         itsDoGrowPrune = decpars.doGrowPrune;
     226          17 :         itsMinPercentChange = decpars.minPercentChange;
     227          17 :         itsVerbose = decpars.verbose;
     228          17 :         itsFastNoise = decpars.fastnoise;
     229          17 :               itsIsInteractive = decpars.interactive;
     230          17 :         itsNsigma = decpars.nsigma;
     231          17 :         itsNoRequireSumwt = true; //decpars.noRequireSumwt;
     232          17 :         itsFullSummary = decpars.fullsummary;
     233             :       }
     234           0 :     catch(AipsError &x)
     235             :       {
     236           0 :         throw( AipsError("Error in constructing a Deconvolver : "+x.getMesg()) );
     237           0 :       }
     238             : 
     239          17 :     itsAddedModel=false;
     240          17 :   }
     241             : 
     242          17 :   Long SynthesisDeconvolver::estimateRAM(const vector<int>& imsize){
     243             : 
     244          17 :     Long mem=0;
     245             :     /* This does not work
     246             :     if( ! itsImages )
     247             :       {
     248             :         itsImages = makeImageStore( itsImageName );
     249             :       }
     250             :     */
     251          17 :     if(itsDeconvolver)
     252          17 :       mem=itsDeconvolver->estimateRAM(imsize);
     253          17 :     return mem;
     254             :   }
     255             : 
     256           0 :   Record SynthesisDeconvolver::initMinorCycle() {
     257             :     /////IMPORTANT initMinorCycle has to be called before setupMask...that order has to be kept !
     258             : 
     259           0 :     if(!itsImages)
     260           0 :       itsImages=makeImageStore(itsImageName, itsNoRequireSumwt);
     261             :     //For cubes as we are not doing a post major cycle residual automasking
     262             :     //Force recalculation of robust stats to update nsigmathreshold with
     263             :     //most recent residual
     264             : 
     265           0 :     if(itsAutoMaskAlgorithm=="multithresh" && itsImages->residual()->shape()[3] >1 && itsNsigma > 0.0){
     266           0 :       Record retval;
     267           0 :       Record backupRobustStats=itsRobustStats;
     268           0 :       itsRobustStats=Record();
     269           0 :       retval=initMinorCycle(itsImages);
     270           0 :       itsRobustStats=backupRobustStats;
     271           0 :       return retval;
     272           0 :     }
     273             : 
     274             :     /* else if (itsAutoMaskAlgorithm=="multithresh" && itsImages->residual()->shape()[3]){
     275             :       ///As the automask for cubes pre-CAS-9386...
     276             :       /// was tuned to look for threshold in future mask
     277             :       ///It is as good as somewhere in between no mask and mask
     278             :       //      Record backupRobustStats=itsRobustStats;
     279             :       Record retval=initMinorCycle(itsImages);
     280             :       //cerr << "INITMINOR " << itsRobustStats << endl;
     281             :       //itsRobustStats=backupRobustStats;
     282             :       if(retval.isDefined("peakresidualnomask")){
     283             :         Float futureRes=Float(retval.asFloat("peakresidualnomask")-(retval.asFloat("peakresidualnomask")-retval.asFloat("peakresidual"))/1000.0);
     284             :         if(futureRes != itsPreviousFutureRes){
     285             :           //itsLoopController.setPeakResidual(retval.asFloat("peakresidualnomask"));
     286             :           retval.define("peakresidual", futureRes);
     287             :           itsPreviousFutureRes=futureRes;
     288             :         }
     289             :       }
     290             :       return retval;
     291             :       }
     292             :     */
     293           0 :     Record retval= initMinorCycle(itsImages);
     294             :     //    cerr << "INITMINOR retval" << retval << endl;
     295             : 
     296           0 :     return retval;
     297           0 :   }
     298           0 :   Record SynthesisDeconvolver::initMinorCycle(std::shared_ptr<SIImageStore> imstor )
     299             :   {
     300           0 :     LogIO os( LogOrigin("SynthesisDeconvolver","initMinorCycle",WHERE) );
     301           0 :     Record returnRecord;
     302           0 :     Timer timer;
     303           0 :     Timer tim;
     304           0 :     tim.mark();
     305             :     try {
     306             : 
     307             :       //os << "---------------------------------------------------- Init (?) Minor Cycles ---------------------------------------------" << LogIO::POST;
     308             : 
     309             :       Int nSubChans, nSubPols;
     310           0 :       nSubChans = imstor->getShape()(3);
     311           0 :       nSubPols = imstor->getShape()(2);
     312           0 :       itsImages = imstor;
     313             : 
     314             :       // If a starting model exists, this will initialize the ImageStore with it. Will do this only once.
     315           0 :       setStartingModel();
     316             : 
     317             :       //itsIterDone is currently only used by automask code so move this to inside setAutomask
     318             :       //itsIterDone += itsLoopController.getIterDone();
     319             : 
     320             :       //      setupMask();
     321             :       //
     322             :       Float masksum;
     323           0 :       if( ! itsImages->hasMask() ) // i.e. if there is no existing mask to re-use...
     324             :           {
     325           0 :           masksum = -1.0;
     326             :       }
     327             :       else
     328             :         {
     329           0 :           masksum = itsImages->getMaskSum();
     330           0 :           itsImages->mask()->unlock();
     331             :         }
     332           0 :       Bool validMask = ( masksum > 0 );
     333             : 
     334             :       //    os << LogIO::NORMAL3 << "****INITMINOR Masksum stuff "<< tim.real() << LogIO::POST;
     335             :       // tim.mark();
     336             : 
     337             :       // Calculate Peak Residual and Max Psf Sidelobe, and fill into SubIterBot.
     338           0 :       Float peakresnomask = itsImages->getPeakResidual();
     339             :       // CAS-14201 : if the mask is all zero, then the peakresinmask is 0
     340           0 :       Float peakresinmask= validMask ? itsImages->getPeakResidualWithinMask() : 0;
     341             :       //os << LogIO::NORMAL3 << "****INITMINOR residual peak "<< tim.real() << LogIO::POST;
     342             :       //tim.mark();
     343           0 :       itsLoopController.setPeakResidual( validMask ? peakresinmask : peakresnomask );
     344             :       //os << LogIO::NORMAL3 << "****INITMINOR OTHER residual peak "<< tim.real() << LogIO::POST;
     345             :       //tim.mark();
     346           0 :       itsLoopController.setPeakResidualNoMask( peakresnomask );
     347           0 :       itsLoopController.setMaxPsfSidelobe( itsImages->getPSFSidelobeLevel() );
     348             : 
     349             :       //re-calculate current nsigma threhold
     350             :       //os<<"Calling calcRobustRMS ....syndeconv."<<LogIO::POST;
     351           0 :       Float nsigmathresh = 0.0;
     352           0 :       Bool useautomask = ( itsAutoMaskAlgorithm=="multithresh" ? true : false);
     353           0 :       Int iterdone = itsLoopController.getIterDone();
     354             : 
     355             :       //cerr << "INIT automask " << useautomask << " alg " << itsAutoMaskAlgorithm << " sigma " << itsNsigma  << endl;
     356           0 :       if ( itsNsigma >0.0) {
     357           0 :         itsMaskHandler->setPBMaskLevel(itsPBMask);
     358           0 :         Array<Double> medians, robustrms;
     359             :         // 2 cases to use existing stats.
     360             :         // 1. automask has run and so the image statistics record has filled
     361             :         // or
     362             :         // 2. no automask but for the first cycle but already initial calcRMS has ran to avoid duplicate
     363             :         //
     364             : 
     365             :         //cerr << "useauto " << useautomask << " nfields " << itsRobustStats.nfields() << " iterdone " << iterdone << endl;
     366           0 :         if ((useautomask && itsRobustStats.nfields()) ||
     367           0 :             (!useautomask && iterdone==0 && itsRobustStats.nfields()) ) {
     368           0 :            os <<LogIO::DEBUG1<<"automask on: check the current stats"<<LogIO::POST;
     369             :            //os<< "itsRobustStats nfield="<< itsRobustStats.nfields() << LogIO::POST;;
     370           0 :            if (itsRobustStats.isDefined("medabsdevmed")) {
     371           0 :              Array<Double> mads;
     372           0 :              itsRobustStats.get(RecordFieldId("medabsdevmed"), mads);
     373           0 :              os<<LogIO::DEBUG1<<"Using robust rms from automask ="<< mads*1.4826 <<LogIO::POST;
     374           0 :              robustrms = mads*1.4826;
     375           0 :            }
     376           0 :            else if(itsRobustStats.isDefined("robustrms")) {
     377           0 :              itsRobustStats.get(RecordFieldId("robustrms"), robustrms);
     378             :            }
     379           0 :            itsRobustStats.get(RecordFieldId("median"), medians);
     380             : 
     381             :         }
     382             :        else { // do own stats calculation
     383           0 :           timer.mark();
     384             : 
     385           0 :           os<<LogIO::DEBUG1<<"Calling calcRobustRMS .. "<<LogIO::POST;
     386           0 :           robustrms = itsImages->calcRobustRMS(medians, itsPBMask, itsFastNoise);
     387             :           os<< LogIO::NORMAL << "time for calcRobustRMS:  real "<< timer.real() << "s ( user " << timer.user()
     388           0 :              <<"s, system "<< timer.system() << "s)" << LogIO::POST;
     389             :           //reset itsRobustStats
     390             :           //cerr << "medians " << medians << " pbmask " << itsPBMask << endl;
     391             :           try {
     392             :             //os<<"current content of itsRobustStats nfields=="<<itsRobustStats.nfields()<<LogIO::POST;
     393           0 :             itsRobustStats.define(RecordFieldId("robustrms"), robustrms);
     394           0 :             itsRobustStats.define(RecordFieldId("median"), medians);
     395             :           }
     396           0 :           catch(AipsError &x) {
     397           0 :             throw( AipsError("Error in storing the robust image statistics") );
     398           0 :           }
     399             : 
     400             :                 //cerr << this << " DOING robust " << itsRobustStats << endl;
     401             :        }
     402             : 
     403             :         /***
     404             :         Array<Double> robustrms =kitsImages->calcRobustRMS(medians, itsPBMask, itsFastNoise);
     405             :         // Before the first iteration the iteration parameters have not been
     406             :         // set in SIMinorCycleController
     407             :         // Use nsigma pass to SynthesisDeconvolver directly for now...
     408             :         //Float nsigma = itsLoopController.getNsigma();
     409             :         ***/
     410             :         Double minval, maxval;
     411           0 :         IPosition minpos, maxpos;
     412             :         //Double maxrobustrms = max(robustrms);
     413           0 :         if(robustrms.empty())
     414           0 :           throw(AipsError("No valid values to deconvolve"));
     415             : 
     416           0 :         minMax(minval, maxval, minpos, maxpos, robustrms);
     417             : 
     418             :         //Float nsigmathresh = nsigma * (Float)robustrms(IPosition(1,0));
     419             :         //nsigmathresh = itsNsigma * (Float)maxrobustrms;
     420           0 :         String msg="";
     421           0 :         if (useautomask) {
     422           0 :           nsigmathresh = (Float)(medians(maxpos)) + itsNsigma * (Float)maxval;
     423           0 :           msg+=" (nsigma*rms + median)";
     424             :         }
     425             :         else {
     426           0 :           nsigmathresh = itsNsigma * (Float)maxval;
     427             :         }
     428           0 :         os << "Current nsigma threshold (maximum along spectral channels ) ="<<nsigmathresh<< msg <<LogIO::POST;
     429           0 :       }
     430             : 
     431           0 :       itsLoopController.setNsigmaThreshold(nsigmathresh);
     432           0 :       itsLoopController.setPBMask(itsPBMask);
     433           0 :       itsLoopController.setFullSummary(itsFullSummary);
     434             : 
     435           0 :       if ( itsAutoMaskAlgorithm=="multithresh" && !initializeChanMaskFlag ) {
     436           0 :         IPosition maskshp = itsImages->mask()->shape();
     437           0 :         Int nchan = maskshp(3);
     438           0 :         itsChanFlag=Vector<Bool>(nchan,False);
     439           0 :         initializeChanMaskFlag=True;
     440             :         // also initialize posmask, which tracks only positive (emission)
     441             : 
     442           0 :         if(!itsPosMask){
     443             :           //itsPosMask = TempImage<Float> (maskshp, itsImages->mask()->coordinates(),SDMaskHandler::memoryToUse());
     444           0 :           itsPosMask=itsImages->tempworkimage();
     445             :           //you don't want to modify this here...
     446             :           //It is set to 0.0 in SIImageStore first time it is created.
     447             :           //itsPosMask->set(0);
     448           0 :           itsPosMask->unlock();
     449             :         }
     450           0 :       }
     451           0 :       os<<LogIO::DEBUG1<<"itsChanFlag.shape="<<itsChanFlag.shape()<<LogIO::POST;
     452             : 
     453             :       /*
     454             :       Array<Double> rmss = itsImages->calcRobustRMS();
     455             :       AlwaysAssert( rmss.shape()[0]>0 , AipsError);
     456             :       cout  << "madRMS : " << rmss << "  with shape : " << rmss.shape() << endl;
     457             :       //itsLoopController.setMadRMS( rmss[0] );
     458             :       */
     459             : 
     460           0 :       if( itsMaskSum != masksum || masksum == 0.0 ) // i.e. mask has changed.
     461             :         {
     462           0 :           itsMaskSum = masksum;
     463           0 :           itsLoopController.setMaskSum( masksum );
     464             :         }
     465             :       else // mask has not changed...
     466             :         {
     467           0 :           itsLoopController.setMaskSum( -1.0 );
     468             :         }
     469           0 :       float psfsidelobelevel = itsImages->getPSFSidelobeLevel();
     470             : 
     471           0 :       returnRecord = itsLoopController.getCycleInitializationRecord();
     472             : 
     473             :       // cerr << "INIT record " << returnRecord << endl;
     474             : 
     475             :       //      itsImages->printImageStats();
     476           0 :       os << " Absolute Peak residual within mask : " << peakresinmask << ", over full image : " << peakresnomask  << LogIO::POST;
     477           0 :       itsImages->releaseLocks();
     478             : 
     479           0 :       os << LogIO::DEBUG2 << "Initialized minor cycle. Returning returnRec" << LogIO::POST;
     480             : 
     481           0 :     } catch(AipsError &x) {
     482           0 :       throw( AipsError("Error initializing the Minor Cycle for "  + itsImageName + " : "+x.getMesg()) );
     483           0 :     }
     484             : 
     485           0 :     return returnRecord;
     486           0 :   }
     487           0 :   void SynthesisDeconvolver::setChanFlag(const Vector<Bool>& chanflag){
     488             :     //ignore if it has not been given a size yet in initminorcycle
     489           0 :     if(itsChanFlag.nelements()==0)
     490           0 :       return;
     491           0 :     if(itsChanFlag.nelements() != chanflag.nelements())
     492           0 :       throw(AipsError("cannot set chan flags for different number of channels"));
     493           0 :     itsChanFlag =chanflag;
     494             : 
     495             :   }
     496           0 :   Vector<Bool> SynthesisDeconvolver::getChanFlag(){
     497           0 :     return itsChanFlag;
     498             :   }
     499           0 :   void SynthesisDeconvolver::setRobustStats(const Record& rec){
     500           0 :     itsRobustStats=Record();
     501           0 :     itsRobustStats=rec;
     502             : 
     503           0 :   }
     504           0 :   Record SynthesisDeconvolver::getRobustStats(){
     505           0 :     return itsRobustStats;
     506             :   }
     507             : 
     508           0 :   Record SynthesisDeconvolver::interactiveGUI(Record& iterRec)
     509             :   {
     510           0 :     LogIO os( LogOrigin("SynthesisDeconvolver","interactiveGUI",WHERE) );
     511           0 :     Record returnRecord;
     512             : 
     513             :     try {
     514             : 
     515             :       // Check that required parameters are present in the iterRec.
     516           0 :       Int niter=0,cycleniter=0,iterdone;
     517           0 :       Float threshold=0.0, cyclethreshold=0.0;
     518           0 :       if( iterRec.isDefined("niter") &&
     519           0 :           iterRec.isDefined("cycleniter") &&
     520           0 :           iterRec.isDefined("threshold") &&
     521           0 :           iterRec.isDefined("cyclethreshold") &&
     522           0 :           iterRec.isDefined("iterdone") )
     523             :         {
     524           0 :           iterRec.get("niter", niter);
     525           0 :           iterRec.get("cycleniter", cycleniter);
     526           0 :           iterRec.get("threshold", threshold);
     527           0 :           iterRec.get("cyclethreshold", cyclethreshold);
     528           0 :           iterRec.get("iterdone",iterdone);
     529             :         }
     530           0 :       else throw(AipsError("SD::interactiveGui() needs valid niter, cycleniter, threshold to start up."));
     531             : 
     532           0 :       if( ! itsImages ) itsImages = makeImageStore( itsImageName, itsNoRequireSumwt );
     533             : 
     534             :       //      SDMaskHandler masker;
     535           0 :       String strthresh = String::toString(threshold)+"Jy";
     536           0 :       String strcycthresh = String::toString(cyclethreshold)+"Jy";
     537             : 
     538           0 :       if( itsMaskString.length()>0 ) {
     539           0 :           itsMaskHandler->fillMask( itsImages, itsMaskString );
     540             :       }
     541             : 
     542           0 :       Int iterleft = niter - iterdone;
     543           0 :       if( iterleft<0 ) iterleft=0;
     544             : 
     545           0 :       Int stopcode = itsMaskHandler->makeInteractiveMask( itsImages, iterleft, cycleniter, strthresh, strcycthresh );
     546             : 
     547           0 :       Quantity qa;
     548           0 :       casacore::Quantity::read(qa,strthresh);
     549           0 :       threshold = qa.getValue(Unit("Jy"));
     550           0 :       casacore::Quantity::read(qa,strcycthresh);
     551           0 :       cyclethreshold = qa.getValue(Unit("Jy"));
     552             : 
     553           0 :       itsIsMaskLoaded=true;
     554             : 
     555           0 :       returnRecord.define( RecordFieldId("actioncode"), stopcode );
     556           0 :       returnRecord.define( RecordFieldId("niter"), iterdone + iterleft );
     557           0 :       returnRecord.define( RecordFieldId("cycleniter"), cycleniter );
     558           0 :       returnRecord.define( RecordFieldId("threshold"), threshold );
     559           0 :       returnRecord.define( RecordFieldId("cyclethreshold"), cyclethreshold );
     560             : 
     561           0 :     } catch(AipsError &x) {
     562           0 :       throw( AipsError("Error in Interactive GUI : "+x.getMesg()) );
     563           0 :     }
     564           0 :     return returnRecord;
     565           0 :   }
     566             : 
     567             : 
     568           0 :   void SynthesisDeconvolver::setMinorCycleControl(const Record& minorCycleControlRec){
     569             :     //Don't know what itsloopcontroller does not need a const record;
     570           0 :     Record lala=minorCycleControlRec;
     571           0 :     itsLoopController.setCycleControls(lala);
     572             : 
     573           0 :   }
     574             : 
     575           0 :   Record SynthesisDeconvolver::executeMinorCycle(Record& minorCycleControlRec)
     576             :   {
     577             :     // LogIO os( LogOrigin("SynthesisDeconvolver","executeMinorCycle",WHERE) );
     578             : 
     579             : 
     580             :     //    itsImages->printImageStats();
     581           0 :     SynthesisUtilMethods::getResource("Start Deconvolver");
     582             :     ///if cube execute cube deconvolution...check on residual shape as itsimagestore return 0 shape sometimes
     583           0 :     if(!itsImages)
     584           0 :       throw(AipsError("Initminor Cycle has not been called yet"));
     585           0 :     if(itsImages->residual()->shape()[3]> 1){
     586           0 :      return  executeCubeMinorCycle(minorCycleControlRec);
     587             :     }
     588             : 
     589             :     //  os << "---------------------------------------------------- Run Minor Cycle Iterations  ---------------------------------------------" << LogIO::POST;
     590           0 :     return executeCoreMinorCycle(minorCycleControlRec);
     591             :     SynthesisUtilMethods::getResource("End Deconvolver");
     592             :   }
     593           0 :   Record SynthesisDeconvolver::executeCoreMinorCycle(Record& minorCycleControlRec)
     594             :   {
     595             : 
     596           0 :     Record returnRecord;
     597             :     try {
     598             :       //      if ( !itsIsInteractive ) setAutoMask();
     599             :       //cerr << "MINORCYCLE control Rec " << minorCycleControlRec << endl;
     600           0 :       itsLoopController.setCycleControls(minorCycleControlRec);
     601           0 :       bool automaskon (false);
     602           0 :       if (itsAutoMaskAlgorithm=="multithresh") {
     603           0 :         automaskon=true;
     604             :       }
     605             :       //itsDeconvolver->deconvolve( itsLoopController, itsImages, itsDeconvolverId, automaskon, itsFastNoise );
     606             :       // include robust stats rec
     607           0 :       itsDeconvolver->deconvolve( itsLoopController, itsImages, itsDeconvolverId, automaskon, itsFastNoise, itsRobustStats, itsFullSummary );
     608             : 
     609           0 :       returnRecord = itsLoopController.getCycleExecutionRecord();
     610             : 
     611             :       //scatterModel(); // This is a no-op for the single-node case.
     612             : 
     613           0 :       itsImages->releaseLocks();
     614             : 
     615           0 :     } catch(AipsError &x) {
     616           0 :       throw( AipsError("Error in running Minor Cycle : "+x.getMesg()) );
     617           0 :     }
     618             : 
     619             : 
     620             : 
     621           0 :     return returnRecord;
     622           0 :   }
     623           0 :   Record SynthesisDeconvolver::executeCubeMinorCycle(Record& minorCycleControlRec, const Int AutoMaskFlag)
     624             :   {
     625           0 :         LogIO os( LogOrigin("SynthesisDeconvolver","executeCubeMinorCycle",WHERE) );
     626           0 :     Record returnRecord;
     627           0 :     Int doAutoMask=AutoMaskFlag;
     628             : 
     629           0 :     SynthesisUtilMethods::getResource("Start Deconvolver");
     630             : 
     631             :     try {
     632             :       //      if ( !itsIsInteractive ) setAutoMask();
     633           0 :       if(doAutoMask < 1){
     634           0 :         itsLoopController.setCycleControls(minorCycleControlRec);
     635             :       }
     636           0 :       else if(doAutoMask==1){
     637           0 :         minorCycleControlRec=itsPreviousIterBotRec_p;
     638             :       }
     639           0 :       CubeMinorCycleAlgorithm cmc;
     640             :       //casa::applicator.defineAlgorithm(cmc);
     641             :       ///argv and argc are needed just to callthe right overloaded init
     642           0 :       Int argc=1;
     643           0 :       char **argv=nullptr;
     644           0 :       applicator.init(argc, argv);
     645           0 :       if(applicator.isController()){
     646           0 :         os << ((AutoMaskFlag != 1) ? "---------------------------------------------------- Run Minor Cycle Iterations  ---------------------------------------------" : "---------------------------------------------------- Run Automask  ---------------------------------------------" )<< LogIO::POST;
     647             :         /*{///TO BE REMOVED
     648             :           LatticeExprNode le( sum( *(itsImages->mask()) ) );
     649             :           os << LogIO::WARN << "#####Sum of mask BEFORE minor cycle " << le.getFloat() << endl;
     650             :             }
     651             :         */
     652           0 :         Timer tim;
     653           0 :         tim.mark();
     654             :         //itsImages->printImageStats();
     655             :         // Add itsIterdone to be sent to child processes ...needed for automask
     656             :         //cerr << "before record " << itsIterDone << " loopcontroller " << itsLoopController.getIterDone() << endl;
     657           0 :         minorCycleControlRec.define("iterdone", itsIterDone);
     658           0 :         if(doAutoMask < 0) // && itsPreviousIterBotRec_p.nfields() >0)
     659           0 :           doAutoMask=0;
     660           0 :         minorCycleControlRec.define("onlyautomask",doAutoMask);
     661           0 :         if(itsPosMask){
     662           0 :           minorCycleControlRec.define("posmaskname", itsPosMask->name());
     663             :         }
     664             :         //Int numprocs = applicator.numProcs();
     665             :         //cerr << "Number of procs: " << numprocs << endl;
     666             : 
     667           0 :           Int numchan=itsImages->residual()->shape()[3];
     668           0 :           Vector<Int> startchans;
     669           0 :           Vector<Int> endchans;
     670           0 :           Int numblocks=numblockchans(startchans, endchans);
     671           0 :           String psfname=itsImages->psf()->name();
     672             : 
     673           0 :           Float psfsidelobelevel=itsImages->getPSFSidelobeLevel();
     674           0 :           String residualname=itsImages->residual()->name();
     675           0 :           String maskname=itsImages->mask()->name();
     676           0 :           String modelname=itsImages->model()->name();
     677             :           ////Need the pb too as calcrobustrms in SynthesisDeconvolver uses it
     678           0 :           String pbname="";
     679           0 :           if(itsImages->hasPB())
     680           0 :             pbname=itsImages->pb()->name();
     681           0 :           itsImages->releaseLocks();
     682             :           ///in lieu of = operator go via record
     683             :           // need to create a proper = operator for SynthesisParamsDeconv
     684           0 :           SynthesisParamsDeconv decpars;
     685             :           ///Will have to create a = operator...right now kludging
     686             :           ///from record has a check that has to be bypassed for just the
     687             :           /// usage as a = operator
     688             :           {
     689           0 :             String tempMaskString= itsDecPars.maskString;
     690           0 :             itsDecPars.maskString="";
     691           0 :             decpars.fromRecord(itsDecPars.toRecord());
     692             :             //return itsDecPars back to its original state
     693           0 :             itsDecPars.maskString=tempMaskString;
     694           0 :           }
     695             :           ///remove starting model as already dealt with in this deconvolver
     696           0 :           decpars.startModel="";
     697             :           ///masking is dealt already by this deconvolver so mask image
     698             :           //is all that is needed which is sent as maskname to subdeconvolver
     699           0 :           decpars.maskString="";
     700           0 :           (decpars.maskList).resize();
     701           0 :           Record decParsRec = decpars.toRecord();
     702             : 
     703             :           /////Now we loop over channels and deconvolve each
     704             :           ///If we do want to do block of channels rather than 1 channel
     705             :           ///at a time chanRange can take that and the trigger to call this
     706             :           ///function in executeMinorCycle has to change.
     707           0 :           Int rank(0);
     708             :           Bool assigned;
     709           0 :           Bool allDone(false);
     710           0 :           Vector<Int> chanRange(2);
     711             :           //Record beamsetRec;
     712           0 :           Vector<Bool> retvals(numblocks, False);
     713           0 :           Vector<Bool> chanFlag(0);
     714           0 :           if(itsChanFlag.nelements()==0){
     715           0 :             itsChanFlag.resize(numchan);
     716           0 :             itsChanFlag.set(False);
     717             :           }
     718           0 :           Record chanflagRec;
     719           0 :           Int indexofretval=0;
     720           0 :           for (Int k=0; k < numblocks; ++k) {
     721             :             //os << LogIO::DEBUG1 << "deconvolving channel "<< k << LogIO::POST;
     722           0 :             assigned=casa::applicator.nextAvailProcess(cmc, rank);
     723             :             //cerr << "assigned "<< assigned << endl;
     724           0 :             while(!assigned) {
     725             :               //cerr << "SErial ? " << casa::applicator.isSerial() << endl;
     726           0 :               rank = casa::applicator.nextProcessDone(cmc, allDone);
     727             :               //cerr << "while rank " << rank << endl;
     728             :               //receiving output of CubeMinorCycleAlgorithm::put
     729             :               //#1
     730           0 :               Vector<Int> chanRangeProcessed;
     731           0 :               casa::applicator.get(chanRangeProcessed);
     732             :               //#2
     733             : 
     734           0 :               Record chanflagRec;
     735           0 :               casa::applicator.get(chanflagRec);
     736             : 
     737             :               //#3
     738           0 :               Record retval;
     739           0 :               casa::applicator.get(retval);
     740             : 
     741           0 :               Vector<Bool> retchanflag;
     742           0 :               chanflagRec.get("chanflag", retchanflag);
     743           0 :               if(retchanflag.nelements() >0)
     744           0 :                 itsChanFlag(Slice(chanRangeProcessed[0], chanRangeProcessed[1]-chanRangeProcessed[0]+1))=retchanflag;
     745           0 :               Record substats=chanflagRec.asRecord("statsrec");
     746           0 :               setSubsetRobustStats(substats, chanRangeProcessed[0], chanRangeProcessed[1], numchan);
     747             : 
     748           0 :               retvals(indexofretval)=(retval.nfields() > 0);
     749           0 :               ++indexofretval;
     750             :               ///might need to merge these retval
     751           0 :               if(doAutoMask <1)
     752           0 :                 mergeReturnRecord(retval, returnRecord, chanRangeProcessed[0]);
     753             :               /*if(retval.nfields())
     754             :                 cerr << k << "deconv rank " << rank << " successful " << endl;
     755             :                else
     756             :                 cerr << k << "deconv rank " << rank << " failed " << endl;
     757             :               */
     758             :               //cerr <<"rank " << rank << " return rec "<< retval << endl;
     759           0 :               assigned = casa::applicator.nextAvailProcess(cmc, rank);
     760             : 
     761           0 :             }
     762             : 
     763             :             ///send process info
     764             :             // put dec sel params #1
     765           0 :             applicator.put(decParsRec);
     766             :             // put itercontrol  params #2
     767           0 :             applicator.put(minorCycleControlRec);
     768             :             // put which channel to process #3
     769           0 :             chanRange[0]=startchans[k];  chanRange[1]=endchans[k];
     770           0 :             applicator.put(chanRange);
     771             :             // psf  #4
     772           0 :             applicator.put(psfname);
     773             :             // residual #5
     774           0 :             applicator.put(residualname);
     775             :             // model #6
     776           0 :             applicator.put(modelname);
     777             :             // mask #7
     778           0 :             applicator.put(maskname);
     779             :             //pb #8
     780           0 :             applicator.put(pbname);
     781             :             //#9 psf side lobe
     782           0 :             applicator.put(psfsidelobelevel);
     783             :             //# put chanflag
     784           0 :             chanFlag.resize();
     785           0 :             chanFlag=itsChanFlag(IPosition(1, chanRange[0]), IPosition(1, chanRange[1]));
     786             : 
     787           0 :             chanflagRec.define("chanflag", chanFlag);
     788           0 :             Record statrec=getSubsetRobustStats(chanRange[0], chanRange[1]);
     789           0 :             chanflagRec.defineRecord("statsrec", statrec);
     790           0 :             applicator.put(chanflagRec);
     791             :             /// Tell worker to process it
     792           0 :             applicator.apply(cmc);
     793             : 
     794           0 :           }
     795             :           // Wait for all outstanding processes to return
     796           0 :           rank = casa::applicator.nextProcessDone(cmc, allDone);
     797           0 :           while (!allDone) {
     798             : 
     799           0 :             Vector<Int> chanRangeProcessed;
     800           0 :             casa::applicator.get(chanRangeProcessed);
     801           0 :             Record chanflagRec;
     802           0 :             casa::applicator.get(chanflagRec);
     803           0 :             Record retval;
     804           0 :             casa::applicator.get(retval);
     805           0 :             Vector<Bool> retchanflag;
     806           0 :             chanflagRec.get("chanflag", retchanflag);
     807           0 :             if(retchanflag.nelements() >0)
     808           0 :               itsChanFlag(Slice(chanRangeProcessed[0], chanRangeProcessed[1]-chanRangeProcessed[0]+1))=retchanflag;
     809           0 :             Record substats=chanflagRec.asRecord("statsrec");
     810           0 :             setSubsetRobustStats(substats, chanRangeProcessed[0], chanRangeProcessed[1], numchan);
     811           0 :             retvals(indexofretval)=(retval.nfields() > 0);
     812           0 :             ++indexofretval;
     813           0 :             if(doAutoMask < 1)
     814           0 :               mergeReturnRecord(retval, returnRecord, chanRangeProcessed[0]);
     815           0 :             if(retval.nfields() >0)
     816             :               //cerr << "deconv remainder rank " << rank << " successful " << endl;
     817           0 :               cerr << "";
     818             :             else
     819           0 :               cerr << "deconv remainder rank " << rank << " failed " << endl;
     820             : 
     821           0 :             rank = casa::applicator.nextProcessDone(cmc, allDone);
     822           0 :             if(casa::applicator.isSerial())
     823           0 :               allDone=true;
     824             : 
     825           0 :           }
     826             : 
     827           0 :           if(anyEQ(retvals, False))
     828           0 :             throw(AipsError("one of more section of the cube failed in deconvolution"));
     829           0 :           if(doAutoMask < 1){
     830           0 :             itsLoopController.incrementMinorCycleCount(returnRecord.asInt("iterdone"));
     831           0 :             itsIterDone+=returnRecord.asInt("iterdone");
     832             :           }
     833           0 :           itsPreviousIterBotRec_p=Record();
     834           0 :           itsPreviousIterBotRec_p=minorCycleControlRec;
     835             :           /*{///TO BE REMOVED
     836             :           LatticeExprNode le( sum( *(itsImages->mask()) ) );
     837             :           os << LogIO::WARN << "#####Sum of mask AFTER minor cycle " << le.getFloat()  << "loopcontroller iterdeconv " << itsLoopController.getIterDone() << endl;
     838             :           }*/
     839             : 
     840           0 :       }///end of if controller
     841             :       /////////////////////////////////////////////////
     842             : 
     843             :       //scatterModel(); // This is a no-op for the single-node case.
     844             : 
     845           0 :       itsImages->releaseLocks();
     846             : 
     847           0 :     } catch(AipsError &x) {
     848             :       //MPI_Abort(MPI_COMM_WORLD, 6);
     849           0 :       throw( AipsError("Error in running Minor Cycle : "+x.getMesg()) );
     850           0 :     }
     851             : 
     852           0 :     SynthesisUtilMethods::getResource("End Deconvolver");
     853             : 
     854           0 :     return returnRecord;
     855           0 :   }
     856             : 
     857             :   // Restore Image.
     858          17 :   void SynthesisDeconvolver::restore()
     859             :   {
     860          34 :     LogIO os( LogOrigin("SynthesisDeconvolver","restoreImage",WHERE) );
     861             : 
     862          17 :     if( ! itsImages )
     863             :       {
     864           0 :         itsImages = makeImageStore( itsImageName, itsNoRequireSumwt );
     865             :       }
     866             : 
     867          17 :     SynthesisUtilMethods::getResource("Restoration");
     868             : 
     869          17 :     itsDeconvolver->restore(itsImages);
     870          17 :     itsImages->releaseLocks();
     871             : 
     872          17 :   }
     873             : 
     874           0 :   void SynthesisDeconvolver::mergeReturnRecord(const Record& inRec, Record& outRec, const Int chan){
     875             : 
     876             :     ///Something has to be done about what is done in SIIterBot_state::mergeMinorCycleSummary if it is needed
     877             :     //int nSummaryFields = SIMinorCycleController::useSmallSummaryminor() ? 6 : SIMinorCycleController::nSummaryFields; // temporary CAS-13683 workaround
     878             :     //int nSummaryFields = SIMinorCycleController::nSummaryFields; // temporary CAS-13683 workaround
     879           0 :     int nSummaryFields = !itsFullSummary ? 7 : SIMinorCycleController::nSummaryFields; // temporary CAS-13683 workaround
     880             : 
     881           0 :     Matrix<Double> summaryminor(nSummaryFields,0);
     882           0 :     if(outRec.isDefined("summaryminor"))
     883           0 :       summaryminor=Matrix<Double>(outRec.asArrayDouble("summaryminor"));
     884           0 :     Matrix<Double> subsummaryminor;
     885           0 :     if(inRec.isDefined("summaryminor"))
     886           0 :       subsummaryminor=Matrix<Double>(inRec.asArrayDouble("summaryminor"));
     887           0 :     if(subsummaryminor.nelements() !=0){
     888             :       ///The 6th element is supposed to be the subimage id
     889           0 :       subsummaryminor.row(5)= subsummaryminor.row(5)+(Double(chan));
     890           0 :       Matrix<Double> newsummary(nSummaryFields, summaryminor.shape()[1]+subsummaryminor.shape()[1]);
     891           0 :       Int ocol=0;
     892           0 :       for (Int col=0; col< summaryminor.shape()[1]; ++col, ++ocol)
     893           0 :         newsummary.column(ocol)=summaryminor.column(col);
     894           0 :       for (Int col=0; col< subsummaryminor.shape()[1]; ++col, ++ocol)
     895           0 :         newsummary.column(ocol)=subsummaryminor.column(col);
     896           0 :       summaryminor.resize(newsummary.shape());
     897           0 :       summaryminor=newsummary;
     898           0 :     }
     899           0 :     outRec.define("summaryminor", summaryminor);
     900             :     //cerr << "inRec summ minor " << inRec.asArrayDouble("summaryminor") << endl;
     901             :     //cerr << "outRec summ minor " << summaryminor << endl;
     902           0 :     outRec.define("iterdone", Int(inRec.asInt("iterdone")+ (outRec.isDefined("iterdone") ? outRec.asInt("iterdone"): Int(0))));
     903           0 :     outRec.define("maxcycleiterdone", outRec.isDefined("maxcycleiterdone") ? max(inRec.asInt("maxcycleiterdone"), outRec.asInt("maxcycleiterdone")) :inRec.asInt("maxcycleiterdone")) ;
     904             : 
     905           0 :     outRec.define("peakresidual", outRec.isDefined("peakresidual") ? max(inRec.asFloat("peakresidual"), outRec.asFloat("peakresidual")) :inRec.asFloat("peakresidual")) ;
     906             : 
     907             :     ///is not necessarily defined it seems
     908           0 :     Bool updatedmodelflag=False;
     909           0 :     if(inRec.isDefined("updatedmodelflag"))
     910           0 :       inRec.get("updatedmodelflag", updatedmodelflag);
     911           0 :     outRec.define("updatedmodelflag", outRec.isDefined("updatedmodelflag") ? updatedmodelflag || outRec.asBool("updatedmodelflag") : updatedmodelflag) ;
     912             : 
     913             : 
     914             : 
     915           0 :   }
     916             :   // get channel blocks
     917           0 :   Int SynthesisDeconvolver::numblockchans(Vector<Int>& startchans, Vector<Int>& endchans){
     918           0 :     Int nchan=itsImages->residual()->shape()[3];
     919             :     //roughly 8e6 pixel to deconvolve per lock/process is a  minimum
     920           0 :     Int optchan= 8e6/(itsImages->residual()->shape()[0])/(itsImages->residual()->shape()[1]);
     921             :     // cerr << "OPTCHAN" << optchan  << endl;
     922           0 :     if(optchan < 10) optchan=10;
     923           0 :     Int nproc= applicator.numProcs() < 2 ? 1 : applicator.numProcs()-1;
     924             :     /*if(nproc==1){
     925             :       startchans.resize(1);
     926             :       endchans.resize(1);
     927             :       startchans[0]=0;
     928             :       endchans[0]=nchan-1;
     929             :       return 1;
     930             :       }
     931             :     */
     932           0 :     Int blksize= nchan/nproc > optchan ? optchan : Int( std::floor(Float(nchan)/Float(nproc)));
     933           0 :     if(blksize< 1) blksize=1;
     934           0 :     Int nblk=Int(nchan/blksize);
     935           0 :     startchans.resize(nblk);
     936           0 :     endchans.resize(nblk);
     937           0 :     for (Int k=0; k < nblk; ++k){
     938           0 :       startchans[k]= k*blksize;
     939           0 :       endchans[k]=(k+1)*blksize-1;
     940             :     }
     941           0 :     if(endchans[nblk-1] < (nchan-1)){
     942           0 :       startchans.resize(nblk+1,True);
     943           0 :       startchans[nblk]=endchans[nblk-1]+1;
     944           0 :       endchans.resize(nblk+1,True);
     945           0 :       endchans[nblk]=nchan-1;
     946           0 :       ++nblk;
     947             :     }
     948             :     //cerr << "nblk " << nblk << " beg " << startchans << " end " << endchans << endl;
     949           0 :     return nblk;
     950             :   }
     951             : 
     952             :   // pbcor Image.
     953           0 :   void SynthesisDeconvolver::pbcor()
     954             :   {
     955           0 :     LogIO os( LogOrigin("SynthesisDeconvolver","pbcor",WHERE) );
     956             : 
     957           0 :     if( ! itsImages )
     958             :       {
     959           0 :         itsImages = makeImageStore( itsImageName, itsNoRequireSumwt );
     960             :       }
     961             : 
     962           0 :     itsDeconvolver->pbcor(itsImages);
     963           0 :     itsImages->releaseLocks();
     964             : 
     965           0 :   }
     966             : 
     967             : 
     968             : 
     969             :   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     970             :   ////    Internal Functions start here.  These are not visible to the tool layer.
     971             :   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     972             : 
     973          17 :   std::shared_ptr<SIImageStore> SynthesisDeconvolver::makeImageStore( String imagename, Bool noRequireSumwt )
     974             :   {
     975          17 :     std::shared_ptr<SIImageStore> imstore;
     976          17 :     if( itsDeconvolver->getAlgorithmName() == "mtmfs" )
     977           0 :       {  imstore.reset( new SIImageStoreMultiTerm( imagename, itsDeconvolver->getNTaylorTerms(), true, noRequireSumwt ) ); }
     978             :     else
     979          17 :       {  imstore.reset( new SIImageStore( imagename, true, noRequireSumwt ) ); }
     980             : 
     981          17 :     return imstore;
     982             : 
     983           0 :   }
     984             : 
     985             : 
     986             :   // #############################################
     987             :   // #############################################
     988             :   // #############################################
     989             :   // #############################################
     990             : 
     991             :   // Set a starting model.
     992           0 :   void SynthesisDeconvolver::setStartingModel()
     993             :   {
     994           0 :     LogIO os( LogOrigin("SynthesisDeconvolver","setStartingModel",WHERE) );
     995             : 
     996           0 :     if(itsAddedModel==true) {return;}
     997             : 
     998             :     try
     999             :       {
    1000             : 
    1001           0 :         if( itsStartingModelNames.nelements()>0 && itsImages )
    1002             :           {
    1003             :             //      os << "Setting " << itsStartingModelNames << " as starting model for deconvolution " << LogIO::POST;
    1004           0 :             itsImages->setModelImage( itsStartingModelNames );
    1005             :           }
    1006             : 
    1007           0 :         itsAddedModel=true;
    1008             : 
    1009             :       }
    1010           0 :     catch(AipsError &x)
    1011             :       {
    1012           0 :         throw( AipsError("Error in setting  starting model for deconvolution: "+x.getMesg()) );
    1013           0 :       }
    1014             : 
    1015           0 :   }
    1016             : 
    1017             :   // Set mask
    1018           0 :   Bool SynthesisDeconvolver::setupMask()
    1019             :   {
    1020             : 
    1021             :     ////Remembet this has to be called only after initMinorCycle
    1022           0 :     LogIO os( LogOrigin("SynthesisDeconvolver","setupMask",WHERE) );
    1023           0 :     if(!itsImages)
    1024           0 :       throw(AipsError("Initminor Cycle has not been called yet"));
    1025             : 
    1026           0 :     Bool maskchanged=False;
    1027             :     //debug
    1028           0 :     if( itsIsMaskLoaded==false ) {
    1029             :       // use mask(s)
    1030           0 :       if(  itsMaskList[0] != "" || itsMaskType == "pb" || itsAutoMaskAlgorithm != "" ) {
    1031             :         // Skip automask for non-interactive mode.
    1032           0 :         if ( itsAutoMaskAlgorithm != "") { // && itsIsInteractive) {
    1033           0 :           os << "[" << itsImages->getName() << "] Setting up an auto-mask"<<  ((itsPBMask>0.0)?" within PB mask limit ":"") << LogIO::POST;
    1034             :           ////For Cubes this is done in CubeMinorCycle
    1035             :           //cerr << this << "SETUP mask " << itsRobustStats << endl;
    1036           0 :           if(itsImages->residual()->shape()[3] ==1)
    1037           0 :             setAutoMask();
    1038           0 :           else if((itsImages->residual()->shape()[3] >1)){
    1039           0 :             Record dummy;
    1040           0 :             executeCubeMinorCycle(dummy, 1);
    1041           0 :           }
    1042             :           /***
    1043             :           if ( itsPBMask > 0.0 ) {
    1044             :             itsMaskHandler->autoMaskWithinPB( itsImages, itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam, itsPBMask);
    1045             :           }
    1046             :           else {
    1047             :             cerr<<"automask by automask.."<<endl;
    1048             :             itsMaskHandler->autoMask( itsImages, itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam);
    1049             :           }
    1050             :           ***/
    1051             :         }
    1052             : 
    1053             :         //else if( itsMaskType=="user" && itsMaskList[0] != "" ) {
    1054           0 :         if( itsMaskType=="user" && itsMaskList[0] != "" ) {
    1055           0 :           os << "[" << itsImages->getName() << "] Setting up a mask from " << itsMaskList  <<  ((itsPBMask>0.0)?" within PB mask limit ":"") << LogIO::POST;
    1056             : 
    1057           0 :           itsMaskHandler->fillMask( itsImages, itsMaskList);
    1058           0 :           if( itsPBMask > 0.0 ) {
    1059           0 :             itsMaskHandler->makePBMask(itsImages, itsPBMask, True);
    1060             :           }
    1061             :         }
    1062           0 :         else if( itsMaskType=="pb") {
    1063           0 :           os << "[" << itsImages->getName() << "] Setting up a PB based mask" << LogIO::POST;
    1064           0 :           itsMaskHandler->makePBMask(itsImages, itsPBMask);
    1065             :         }
    1066             : 
    1067           0 :         os << "----------------------------------------------------------------------------------------------------------------------------------------" << LogIO::POST;
    1068             : 
    1069             :         }
    1070             :         else {
    1071             :             // new im statistics creates an empty mask and need to take care of that case
    1072           0 :             Bool emptyMask(False);
    1073           0 :             if( itsImages->hasMask() )
    1074             :             {
    1075             :                 // CAS-14203 - Check if mask is empty AND user didn't specify an empty mask
    1076           0 :                 if (itsImages->getMaskSum()==0.0 && itsMaskList[0] != "") {
    1077           0 :                     emptyMask=True;
    1078             :                 }
    1079             :             }
    1080           0 :             if( ! itsImages->hasMask() || emptyMask ) // i.e. if there is no existing mask to re-use...
    1081             :             {
    1082           0 :                 LatticeLocker lock1 (*(itsImages->mask()), FileLocker::Write);
    1083           0 :                 if( itsIsInteractive ) itsImages->mask()->set(0.0);
    1084           0 :                 else itsImages->mask()->set(1.0);
    1085           0 :                 os << "[" << itsImages->getName() << "] Initializing new mask to " << (itsIsInteractive?"0.0 for interactive drawing":"1.0 for the full image") << LogIO::POST;
    1086           0 :             }
    1087             :             else {
    1088           0 :                 os << "[" << itsImages->getName() << "] Initializing to existing mask" << LogIO::POST;
    1089             :             }
    1090             :         }
    1091             : 
    1092             :       // If anything other than automasking, don't re-make the mask here.
    1093           0 :       if ( itsAutoMaskAlgorithm == "" )
    1094           0 :         {       itsIsMaskLoaded=true; }
    1095             : 
    1096             :       // Get the number of mask pixels (sum) and send to the logger.
    1097           0 :       Float masksum = itsImages->getMaskSum();
    1098           0 :       Float npix = (itsImages->getShape()).product();
    1099             : 
    1100             :       //Int npix2 = 20000*20000*16000*4;
    1101             :       //Float npix2f = 20000*20000*16000*4;
    1102             : 
    1103             :       //cout << " bigval : " << npix2 << " and " << npix2f << endl;
    1104             : 
    1105           0 :       os << "[" << itsImages->getName() << "] Number of pixels in the clean mask : " << masksum << " out of a total of " << npix << " pixels. [ " << 100.0 * masksum/npix << " % ]" << LogIO::POST;
    1106             : 
    1107           0 :       maskchanged=True;
    1108             :     }
    1109             :     else {
    1110             :     }
    1111             : 
    1112           0 :     itsImages->mask()->unlock();
    1113           0 :     return maskchanged;
    1114           0 : }
    1115             : 
    1116           0 :   void SynthesisDeconvolver::setAutoMask()
    1117             :   {
    1118             :      //modify mask using automask otherwise no-op
    1119           0 :      if ( itsAutoMaskAlgorithm != "" )  {
    1120           0 :        itsIterDone += itsLoopController.getIterDone();
    1121             : 
    1122             : 
    1123             : 
    1124           0 :        Bool isThresholdReached = itsLoopController.isThresholdReached();
    1125             :              //cerr << this << " setAuto " << itsRobustStats << endl;
    1126           0 :        LogIO os( LogOrigin("SynthesisDeconvolver","setAutoMask",WHERE) );
    1127           0 :        os << "Generating AutoMask" << LogIO::POST;
    1128             :        //os << LogIO::WARN << "#####ItsIterDone value " << itsIterDone << endl;
    1129             : 
    1130             :        //os << "itsMinPercentChnage = " << itsMinPercentChange<< LogIO::POST;
    1131             :        //cerr << "SUMa of chanFlag before " << ntrue(itsChanFlag) << endl;
    1132           0 :        if ( itsPBMask > 0.0 ) {
    1133             :          //itsMaskHandler->autoMaskWithinPB( itsImages, itsPosMask, itsIterDone, itsChanFlag, itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam, itsNMask, itsAutoAdjust,  itsSidelobeThreshold, itsNoiseThreshold, itsLowNoiseThreshold, itsNegativeThreshold,itsCutThreshold, itsSmoothFactor, itsMinBeamFrac, itsGrowIterations, itsDoGrowPrune, itsMinPercentChange, itsVerbose, itsFastNoise, isThresholdReached, itsPBMask);
    1134             :          //pass robust stats
    1135           0 :          itsMaskHandler->autoMaskWithinPB( itsImages, *itsPosMask, itsIterDone, itsChanFlag, itsRobustStats, itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam, itsNMask, itsAutoAdjust,  itsSidelobeThreshold, itsNoiseThreshold, itsLowNoiseThreshold, itsNegativeThreshold,itsCutThreshold, itsSmoothFactor, itsMinBeamFrac, itsGrowIterations, itsDoGrowPrune, itsMinPercentChange, itsVerbose, itsFastNoise, isThresholdReached, itsPBMask);
    1136             :        }
    1137             :        else {
    1138             :          //itsMaskHandler->autoMask( itsImages, itsPosMask, itsIterDone, itsChanFlag,itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam, itsNMask, itsAutoAdjust, itsSidelobeThreshold, itsNoiseThreshold, itsLowNoiseThreshold, itsNegativeThreshold, itsCutThreshold, itsSmoothFactor, itsMinBeamFrac, itsGrowIterations, itsDoGrowPrune, itsMinPercentChange, itsVerbose, itsFastNoise, isThresholdReached );
    1139             : 
    1140             :         // pass robust stats
    1141           0 :         itsMaskHandler->autoMask( itsImages, *itsPosMask, itsIterDone, itsChanFlag, itsRobustStats, itsAutoMaskAlgorithm, itsMaskThreshold, itsFracOfPeak, itsMaskResolution, itsMaskResByBeam, itsNMask, itsAutoAdjust, itsSidelobeThreshold, itsNoiseThreshold, itsLowNoiseThreshold, itsNegativeThreshold, itsCutThreshold, itsSmoothFactor, itsMinBeamFrac, itsGrowIterations, itsDoGrowPrune, itsMinPercentChange, itsVerbose, itsFastNoise, isThresholdReached );
    1142             :        }
    1143             :        //cerr <<this << " SETAutoMask " << itsRobustStats << endl;
    1144             :        //cerr << "SUM of chanFlag AFTER " << ntrue(itsChanFlag) << endl;
    1145           0 :      }
    1146           0 :   }
    1147             : 
    1148             :   // check if restoring beam is reasonable
    1149          17 :   void SynthesisDeconvolver::checkRestoringBeam()
    1150             :   {
    1151          34 :     LogIO os( LogOrigin("SynthesisDeconvolver","checkRestoringBeam",WHERE) );
    1152             :     //check for a bad restoring beam
    1153          17 :     GaussianBeam beam;
    1154             : 
    1155          17 :     if( ! itsImages ) itsImages = makeImageStore( itsImageName, itsNoRequireSumwt );
    1156          17 :     ImageInfo psfInfo = itsImages->psf()->imageInfo();
    1157          17 :     if (psfInfo.hasSingleBeam()) {
    1158          17 :       beam = psfInfo.restoringBeam();
    1159             :     }
    1160           0 :     else if (psfInfo.hasMultipleBeams() && itsUseBeam=="common") {
    1161           0 :       beam = CasaImageBeamSet(psfInfo.getBeamSet()).getCommonBeam();
    1162             :     }
    1163          17 :     Double beammaj = beam.getMajor(Unit("arcsec"));
    1164          17 :     Double beammin = beam.getMinor(Unit("arcsec"));
    1165          17 :     if (std::isinf(beammaj) || std::isinf(beammin)) {
    1166           0 :       String msg;
    1167           0 :       if (itsUseBeam=="common") {
    1168           0 :         msg+="Bad restoring beam using the common beam (at least one of the beam axes has an infinite size)  ";
    1169           0 :         throw(AipsError(msg));
    1170             :       }
    1171           0 :     }
    1172          17 :     itsImages->releaseLocks();
    1173          17 :   }
    1174             : 
    1175             :   // This is for interactive-clean.
    1176           0 :   void SynthesisDeconvolver::getCopyOfResidualAndMask( TempImage<Float> &/*residual*/,
    1177             :                                            TempImage<Float> &/*mask*/ )
    1178             :   {
    1179             :     // Actually all I think we need here are filenames JSK 12/12/12
    1180             :     // resize/shape and copy the residual image and mask image to these in/out variables.
    1181             :     // Allocate Memory here.
    1182           0 :   }
    1183           0 :   void SynthesisDeconvolver::setMask( TempImage<Float> &/*mask*/ )
    1184             :   {
    1185             :     // Here we will just pass in the new names
    1186             :     // Copy the input mask to the local main image mask
    1187           0 :   }
    1188           0 :   void SynthesisDeconvolver::setIterDone(const Int iterdone){
    1189             :     //cerr << "SETITERDONE iterdone " << iterdone << endl;
    1190             :     ///this get lost in initMinorCycle
    1191             :     //itsLoopController.incrementMinorCycleCount(iterdone);
    1192           0 :     itsIterDone=iterdone;
    1193             : 
    1194           0 :   }
    1195           0 :   void SynthesisDeconvolver::setPosMask(std::shared_ptr<ImageInterface<Float> > posmask){
    1196           0 :     itsPosMask=posmask;
    1197             : 
    1198           0 :   }
    1199             : 
    1200           0 :   auto key2Mat = [](const Record& rec, const String& key, const Int npol) {
    1201           0 :      Matrix<Double> tmp;
    1202             :      //cerr << "KEY2mat " << key <<"  "<< rec.asArrayDouble(key).shape() << endl;
    1203           0 :      if(rec.asArrayDouble(key).shape().nelements()==1){
    1204           0 :        if(rec.asArrayDouble(key).shape()[0] != npol){
    1205           0 :          tmp.resize(1,rec.asArrayDouble(key).shape()[0]);
    1206           0 :          Vector<Double>tmpvec=rec.asArrayDouble(key);
    1207           0 :          tmp.row(0)=tmpvec;
    1208           0 :        }
    1209             :        else{
    1210           0 :          tmp.resize(rec.asArrayDouble(key).shape()[0],1);
    1211           0 :          Vector<Double>tmpvec=rec.asArrayDouble(key);
    1212           0 :          tmp.column(0)=tmpvec;
    1213           0 :        }
    1214             : 
    1215             :      }
    1216             :      else{
    1217           0 :        tmp=rec.asArrayDouble(key);
    1218             :      }
    1219           0 :      return tmp;
    1220           0 :    };
    1221             : 
    1222           0 :   Record SynthesisDeconvolver::getSubsetRobustStats(const Int chanBeg, const Int chanEnd){
    1223           0 :     Record outRec;
    1224             :     //cerr << "getSUB " << itsRobustStats << endl;
    1225           0 :     if(itsRobustStats.nfields()==0)
    1226           0 :       return outRec;
    1227           0 :     Matrix<Double> tmp;
    1228           0 :     std::vector<String> keys={"min", "max", "rms", "medabsdevmed", "med", "robustrms", "median"};
    1229           0 :     for (auto it = keys.begin() ; it != keys.end(); ++it){
    1230           0 :       if(itsRobustStats.isDefined(*it)){
    1231           0 :         tmp.resize();
    1232           0 :         tmp=key2Mat(itsRobustStats, *it, itsImages->residual()->shape()[2]);
    1233             :         /*
    1234             :         cerr << "size of " << *it << "   " << itsRobustStats.asArrayDouble(*it).shape() << endl;
    1235             :         if(itsRobustStats.asArrayDouble(*it).shape().nelements()==1){
    1236             :           tmp.resize(1, itsRobustStats.asArrayDouble(*it).shape()[0]);
    1237             :           Vector<Double>tmpvec=itsRobustStats.asArrayDouble(*it);
    1238             :           tmp.row(0)=tmpvec;
    1239             : 
    1240             :         }
    1241             :         else
    1242             :           tmp=itsRobustStats.asArrayDouble(*it);
    1243             :         */
    1244             :         //      cerr << std::setprecision(12) << tmp[chanBeg] << " bool " <<(tmp[chanBeg]> (DBL_MAX-(DBL_MAX*1e-15))) << endl;
    1245           0 :         if(tmp(0,chanBeg)> (DBL_MAX-(DBL_MAX*1e-15)))
    1246           0 :           return Record();
    1247             :         //cerr << "GETSUB blc "<< IPosition(2, 0, chanBeg)<<  " trc " << IPosition(2, tmp.shape()[0]-1, chanEnd) << " shape " << tmp.shape() << endl;
    1248           0 :         outRec.define(*it, tmp(IPosition(2, 0, chanBeg), IPosition(2, tmp.shape()[0]-1, chanEnd)));
    1249             :       }
    1250             :     }
    1251             : 
    1252             :     // When itsImages->residual() is called, it (sometimes) creates a read-lock. Release that lock.
    1253           0 :     shared_ptr<ImageInterface<Float> > resimg = itsImages->residual();
    1254           0 :     itsImages->releaseImage( resimg );
    1255             : 
    1256             :     //cerr <<"chanbeg " << chanBeg << " chanend " << chanEnd << endl;
    1257             :     //cerr << "GETSUB " << outRec << endl;
    1258           0 :     return outRec;
    1259           0 :   }
    1260             : 
    1261           0 :   void SynthesisDeconvolver::setSubsetRobustStats(const Record& inrec, const Int chanBeg, const Int chanEnd, const Int numchan){
    1262           0 :     if(inrec.nfields()==0)
    1263           0 :       return ;
    1264           0 :     Matrix<Double> tmp;
    1265           0 :     std::vector<String> keys={"min", "max", "rms", "medabsdevmed", "med", "robustrms", "median"};
    1266             : 
    1267           0 :     for (auto it = keys.begin() ; it != keys.end(); ++it){
    1268           0 :       if(inrec.isDefined(*it)){
    1269           0 :         tmp.resize();
    1270           0 :         tmp=key2Mat(inrec, *it,itsImages->residual()->shape()[2] );
    1271           0 :         Matrix<Double> outvec;
    1272           0 :         if(itsRobustStats.isDefined(*it)){
    1273           0 :           outvec=key2Mat(itsRobustStats, *it, itsImages->residual()->shape()[2]);
    1274             :         }
    1275             :         else{
    1276           0 :           outvec.resize(itsImages->residual()->shape()[2], numchan);
    1277           0 :           outvec.set(DBL_MAX);
    1278             :         }
    1279             : 
    1280             : 
    1281           0 :         outvec(IPosition(2, 0, chanBeg), IPosition(2,outvec.shape()[0]-1, chanEnd))=tmp;
    1282           0 :         itsRobustStats.define(*it, outvec);
    1283           0 :       };
    1284             :     }
    1285             : 
    1286             :     // When itsImages->residual() is called, it (sometimes) creates a read-lock. Release that lock.
    1287           0 :     shared_ptr<ImageInterface<Float> > resimg = itsImages->residual();
    1288           0 :     itsImages->releaseImage( resimg );
    1289             : 
    1290             :     //cerr << "SETT " << itsRobustStats << endl;
    1291             :     //cerr << "SETT::ItsRobustStats " << Vector<Double>(itsRobustStats.asArrayDouble("min")) << endl;
    1292           0 :   }
    1293             : } //# NAMESPACE CASA - END
    1294             : 

Generated by: LCOV version 1.16