//# Copyright (C) 1997,1998,1999,2000,2001,2002,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id: MultiTermMatrixCleaner.cc 13656 2010-12-04 02:08:02 UrvashiRV$ // Same include list as in MatrixCleaner.cc #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Additional include files #include #include #include #include using namespace casacore; namespace casa { //# NAMESPACE CASA - BEGIN #define MIN(a,b) ((a)<=(b) ? (a) : (b)) #define MAX(a,b) ((a)>=(b) ? (a) : (b)) MultiTermMatrixCleaner::MultiTermMatrixCleaner(): MatrixCleaner(), ntaylor_p(0),psfntaylor_p(0),nscales_p(0),nx_p(0),ny_p(0),totalIters_p(0), maxscaleindex_p(0), globalmaxpos_p(IPosition(0)), /*donePSF_p(false),*/donePSP_p(false),doneCONV_p(false),memoryMB_p(0), adbg(false) { } /* MultiTermMatrixCleaner::MultiTermMatrixCleaner(const MultiTermMatrixCleaner & other): MatrixCleaner(),ntaylor_p(other.ntaylor_p) //And others... minus some... { } MultiTermMatrixCleaner &MultiTermMatrixCleaner:: operator=(const MultiTermMatrixCleaner & other) { operator=(other); return *this; } */ MultiTermMatrixCleaner::~MultiTermMatrixCleaner() { //cout << "In MultiTermMatrixCleaner destructor" << endl; } Bool MultiTermMatrixCleaner::setscales(const Vector & scales) { nscales_p = scales.nelements(); scaleSizes_p.resize(); scaleSizes_p = scales; totalScaleFlux_p.resize(nscales_p); totalScaleFlux_p.set(0.0); maxScaleVal_p.resize(nscales_p); maxScaleVal_p.set(0.0); maxScalePos_p.resize(nscales_p); globalmaxval_p=-1e+10; globalmaxpos_p=IPosition(2,0); maxscaleindex_p=0; return true; } Bool MultiTermMatrixCleaner::setntaylorterms(const int & nterms) { ntaylor_p = nterms; psfntaylor_p = 2*nterms-1; totalTaylorFlux_p.resize(ntaylor_p); totalTaylorFlux_p.set(0.0); return true; } // Allocate memory, based on nscales and ntaylor Bool MultiTermMatrixCleaner::initialise(Int nx, Int ny) { LogIO os(LogOrigin("MultiTermMatrixCleaner", "initialise()", WHERE)); /* Verify Image Shapes */ // nx_p = model.shape(0); nx_p = nx; ny_p = ny; if(adbg) os << "Checking shapes" << LogIO::POST; /* Verify nscales_p and ntaylor_p */ AlwaysAssert(nscales_p>0, AipsError); AlwaysAssert(ntaylor_p>0, AipsError); AlwaysAssert(scaleSizes_p.nelements()==static_cast(nscales_p), AipsError); if(adbg) os << "Verify Scale sizes" << LogIO::POST; verifyScaleSizes(); /* Calculate PSF/scale support - after verifying scale sizes and before allocating memory */ // PSF support : main lobe width x how many times this width the patch should cover Float maxscalesize = scaleSizes_p[nscales_p-1]; //// N times the size of the main lobe of the PSF at the max scale size Float psfbeam = 4.0; Float nbeams = 20.0; Int psupport = findBeamPatch(maxscalesize, nx_p, ny_p, psfbeam, nbeams); // //----------------------Encapsulated in the findBeamPatch() method from here...----------- // Int psupport = (Int) ( sqrt( psfbeam*psfbeam + maxscalesize*maxscalesize ) * nbeams ); // // At least this big... // if(psupport < psfbeam*nbeams ) psupport = static_cast(psfbeam*nbeams); // // Not too big... // if(psupport > nx_p || psupport > ny_p) psupport = MIN(nx_p,ny_p); // // Make it even. // if (psupport%2 != 0) psupport -= 1; // //----------------------...till here------------------------------------ // Full image //psfsupport_p = IPosition(2,MIN(nx_p,ny_p),MIN(nx_p,ny_p)); //psfpeak_p = IPosition(2,nx_p/2, ny_p/2); // Inner quater image //psfsupport_p = IPosition(2,MIN(nx_p/2,ny_p/2),MIN(nx_p/2,ny_p/2)); //psfpeak_p = IPosition(2,nx_p/4, ny_p/4); // Generic support-size. psfsupport_p = IPosition(2,psupport,psupport); psfpeak_p = IPosition(2,psupport/2, psupport/2); os << "Using a PSF patch of " << psupport << " pixels on each side for minor-cycle updates." << endl; /* Force the scale images to be */ if(adbg) os << "Start allocating mem" << LogIO::POST; /* Allocate memory for many many TempMatrices. */ /* Check on a return value of -1 - for insuffucient memory */ if( allocateMemory() == -1 ) return false; /* FFTServer */ fftcomplex = FFTServer(IPosition(2,nx_p,ny_p)); /* Create the scale functions and their FTs */ setupScaleFunctions(); totalIters_p=0; prev_max_p = 1e+10; min_max_p = 1e+10; rmaxval_p = -1.0; if(adbg) os << "Finished initializing MultiTermMatrixCleaner" << LogIO::POST; return true; } Bool MultiTermMatrixCleaner::buildImagePatches() { gip = IPosition(2,nx_p,ny_p); /* The update region. */ IPosition inc(2,1,1); blc_p = IPosition(globalmaxpos_p - psfsupport_p/2); trc_p = IPosition(globalmaxpos_p + psfsupport_p/2 - IPosition(2,1,1)); //cout << "residual box 1 : " << blc << trc << endl; LCBox::verify(blc_p, trc_p, inc, gip); //cout << "residual box 2 : " << blc << trc << endl; /* Shifted region, with the psf at the globalmaxpos_p. */ blcPsf_p = IPosition(blc_p + psfpeak_p - globalmaxpos_p); // OLD trcPsf_p = IPosition(trc_p + psfpeak_p - globalmaxpos_p); // OLD //cout << "psf box 1 : " << blcPsf << trcPsf << endl; LCBox::verify(blcPsf_p, trcPsf_p, inc, psfsupport_p); // NEW //cout << "psf box 2 : " << blcPsf << trcPsf << endl; /* Reconcile box sizes/locations with the image size */ makeBoxesSameSize(blc_p,trc_p,blcPsf_p,trcPsf_p); //cout << "maxpos : " << globalmaxpos_p << " blc : " << blc_p << " trc : " << trc_p << " blcPsf : " << blcPsf_p << " trcPsf : " << trcPsf_p << endl; return true; } Bool MultiTermMatrixCleaner::setpsf(int order, Matrix & psf) { AlwaysAssert((order>=(int)0 && order<(int)vecPsfFT_p.nelements()), AipsError); if(order==0) AlwaysAssert(validatePsf(psf), AipsError); // Directly store the FFT of the PSFs. // The FT'd matrix is reshaped automatically. fftcomplex.fft0(vecPsfFT_p[order],psf,false); //fftcomplex.flip(vecPsfFT_p[order],false,false); // Matrix temp(real(vecPsfFT_p[order])); // writeMatrixToDisk("psfFT_"+String::toString(order), temp); return true; } /* Input : Dirty Images */ Bool MultiTermMatrixCleaner::setresidual(int order, Matrix & dirty) { AlwaysAssert((order>=(int)0 && order<(int)vecDirty_p.nelements()), AipsError); vecDirty_p[order].reference(dirty); return true; } /* Input : Model Component Image */ //TODO : This is an extra copy of the model image. Why not hold it by reference ??? Bool MultiTermMatrixCleaner::setmodel(int order, Matrix & model) { AlwaysAssert((order>=(int)0 && order<(int)vecModel_p.nelements()), AipsError); vecModel_p[order].assign(model); totalTaylorFlux_p[order] = (sum(vecModel_p[order])); return true; } /* Input : Mask */ Bool MultiTermMatrixCleaner::setmask(Matrix & mask) { if(itsMask.null()) itsMask = new Matrix(mask); // it's a counted ptr else { AlwaysAssert(itsMask->shape()==mask.shape(), AipsError); (*itsMask).assign(mask); } return true; } /* Output : Model Component Image */ Bool MultiTermMatrixCleaner::getmodel(int order, Matrix & model) { AlwaysAssert((order>=(int)0 && order<(int)vecModel_p.nelements()), AipsError); model.assign(vecModel_p[order]); return true; } /* Output Residual Image */ Bool MultiTermMatrixCleaner::getresidual(int order, Matrix & residual) { AlwaysAssert((order>=(int)0 && order<(int)vecDirty_p.nelements()), AipsError); //AlwaysAssert(residual, AipsError); residual.assign(vecDirty_p[order]); ///residual.assign( matR_p[IND2(order,0)] ); // This is the one that gets updated during iters. return true; } /* Output Hessian matrix */ Bool MultiTermMatrixCleaner::getinvhessian(Matrix & invhessian) { invhessian.resize((invMatA_p[0]).shape()); invhessian = (invMatA_p[0]); return true; } /* Do the deconvolution */ Int MultiTermMatrixCleaner::mtclean(Int maxniter, Float stopfraction, Float inputgain, Float userthreshold) { LogIO os(LogOrigin("MultiTermMatrixCleaner", "mtclean()", WHERE)); if(adbg)os << "SOLVER for Multi-Frequency Synthesis deconvolution" << LogIO::POST; /* Initialize some variables */ maxniter_p = maxniter; stopfraction_p= stopfraction; inputgain_p=inputgain; userthreshold_p=userthreshold; //cout << "MTMC : User threshold : " << userthreshold_p << endl; Int convergedflag = 0; Float fluxlimit = -1; Float loopgain = 0.5; if(inputgain>(Float)0.0) loopgain=inputgain; Int criterion=5; // This chooses among a list of 'penalty functions' itercount_p=0; Int iterdone = 0; /* Compute all convolutions and the matrix A */ /* If matrix is not invertible, return ! */ /* This is done only once - for the first major cycle. Null operation otherwise */ if( doneCONV_p == false ) { if( computeHessianPeak() == -2 ) return -2; } /* Set up the Mask image */ /* This must be after the Hessian is computed.. */ setupUserMask(); /* Compute the convolutions of the current residual with all PSFs and scales */ os << "Calculating convolutions of residual images with scales " << LogIO::POST; computeRHS(); /* Check if peak RHS is already less than the threshold */ /* This step computes the flux limit also - when called here... */ convergedflag = checkConvergence(criterion,fluxlimit,loopgain); if(convergedflag==1) return 0; /* Compute the flux limits that determine the depth of the minor cycles. */ // computeFluxLimit(fluxlimit,thresh); /********************** START MINOR CYCLE ITERATIONS ***********************/ //os << "Doing deconvolution iterations..." << LogIO::POST; for(itercount_p=0;itercount_p globalmaxval_p) { globalmaxval_p = maxScaleVal_p[scale]*scaleBias_p[scale]; globalmaxpos_p = maxScalePos_p[scale]; maxscaleindex_p = scale; } } /* Update the image and psf patch sizes according to the current globalmaxval and psfsupport. This patch is over which the next-iteration's solveMatrixEqn is computed */ buildImagePatches(); /* Update the current solution by this chosen step */ updateModelAndRHS(loopgain); /* Increment iteration count */ totalIters_p++; iterdone++; /* Check for convergence */ convergedflag = checkConvergence(criterion,fluxlimit,loopgain); /* Reached stopping threshold for this major cycle */ /* Break out of minor-cycle loop, but signal that major cycles should continue */ if(convergedflag) { break; } }//end minor cycle if(convergedflag==0) { os << "Reached max number of iterations for this minor cycle " << LogIO::POST; } /* returning because of non-convergence */ if(convergedflag == -1) { os << "Stopping minor cycle iterations because of possible divergence." << LogIO::POST; //return(-1); } /********************** END MINOR CYCLE ITERATIONS ***********************/ /* Print out flux counts so far */ //if(adbg) { os << "Total flux by scale :"; for(Int scale=0;scale scaleflags(nscales_p); scaleflags=0; for(Int scale=0;scale nx_p/2 || scaleSizes_p[scale] > ny_p/2) { scaleflags[scale]=1; os << LogIO::WARN << "Scale size of " << scaleSizes_p[scale] << " pixels is too big for an image size of " << nx_p << " x " << ny_p << " pixels. This scale size will be ignored. " << LogIO::POST; } } if(sum(scaleflags)>0) // prune the scalevector and change nscales_p { Vector newscalesizes(nscales_p - sum(scaleflags)); uInt i=0; for(Int scale=0;scale(( nx_p*ny_p*4*(ntempfull + ntemphalf/2.0) + psfsupport_p[0]*psfsupport_p[1]*nHess )/(1024*1024)); memoryMB_p = Double(HostInfo::memoryTotal()/1024); if(adbg) os << "This algorithm needs to allocate " << numMB << " MBytes." << LogIO::POST; if (numMB > 0.75*memoryMB_p) { os << LogIO::WARN << "This algorithm needs to allocate " << numMB << " MBytes for " << ntempfull + ntemphalf << " Matrices. " << LogIO::POST; os << LogIO::WARN << "Available memory for this process is " << memoryMB_p << " MB. Please reduce imsize/nscales/nterms and try again " << LogIO::POST; return -1; } // shape of all matrices gip = IPosition(2,nx_p,ny_p); IPosition tgip(2,ntaylor_p,ntaylor_p); // Small HessianPeak matrix to be inverted for each point.. matA_p.resize(nscales_p); invMatA_p.resize(nscales_p); for(Int i=0;i maskft; fftcomplex.fft0(maskft , *itsMask , false); for(Int scale=0;scaleshape())(1); ++j) for (Int k =0 ; k < (itsMask->shape())(0); ++k) { if(itsMaskThreshold > (Float)0.0) // if negative, use the continuous mask { (vecScaleMasks_p[scale])(k,j) = (vecScaleMasks_p[scale])(k,j) > (Float)0.1 ? 1.0 : 0.0; } } // writeMatrixToDisk("scalemask."+String::toString(scale), vecScaleMasks_p[scale]); }// end of for scale /* TO DO... maybe : Map some local variables to those in the parant MatrixCleaner class so that its functions can be used. Later, clean this up by directly using the MatrixCleaner variables. Currently not possible because the function that creates scales and populates itsScaleXfrs (setscales), does a lot of extra stuff that we don't need here. */ /* Must reuse itsNscales, itsScaleSizes, itsScales, itsScaleXfrs, itsScaleMasks, itsScalesValid and eliminate : vecScales_p, scaleSizes_p, vecScalesFT_p, vecScaleMasks_p */ /* itsScaleXfrs.resize(nscales_p); itsNscales = nscales_p; for(Int scale=0;scale1) { for(Int scale=0;scale psfpatch = ( vecWork_p[0] ) (immid-psfsupport_p/2,immid+psfsupport_p/2-IPosition(2,1,1)); vecScales_p[scale] = psfpatch; } donePSP_p=true; } return 0; }/* end of setupBlobs() */ /*************************************** * Compute convolutions and the A matrix. ****************************************/ Int MultiTermMatrixCleaner::computeHessianPeak() { LogIO os(LogOrigin("MultiTermMatrixCleaner", "computeHessianPeak", WHERE)); gip = IPosition(2,nx_p,ny_p); if(!doneCONV_p) { // Compute the convolutions of the smoothed psfs with each other. // Compute Assxx // Compute A100, A101, A102 // A110, A111, A112 // A120, A121, A122 for h(s1) // Compute A200, A201, A202 // A210, A211, A212 // A220, A221, A222 for h(s2) //... depending on the number of scales chosen // (PSF * scale) * (PSF * scale) -> cubeA_p [nx_p,ny_p,ntaylor,ntaylor,nscales] os << "Calculating PSF and Scale convolutions " << LogIO::POST; for (Int taylor1=0; taylor1 psfpatch = ( vecWork_p[0] ) (itsPositionPeakPsf-psfsupport_p/2,itsPositionPeakPsf+psfsupport_p/2-IPosition(2,1,1)); cubeA_p[IND4(taylor1,taylor2,scale1,scale2)] = psfpatch; } else { fftcomplex.fft0( cubeA_p[IND4(taylor1,taylor2,scale1,scale2)] , cWork_p , false ); } //writeMatrixToDisk("psfconv_t_"+String::toString(taylor1)+"-"+String::toString(taylor2)+"_s_"+String::toString(scale1)+"-"+String::toString(scale2)+".im", cubeA_p[IND4(taylor1,taylor2,scale1,scale2)] ); } // Construct A, invA for each scale. if(itsPositionPeakPsf != IPosition(2,(nx_p/2),(ny_p/2))) os << LogIO::WARN << "The PSF peak is not at the center of the image..." << LogIO::POST; Int stopnow=false; for (Int scale=0; scale ratios(ntaylor_p); Float tsum=0.0; for(Int taylor1=0; taylor1 the Right-Hand-Side of the matrix equation. ****************************************/ Int MultiTermMatrixCleaner::computeRHS() { // LogIO os(LogOrigin("MultiTermMatrixCleaner", "computeRHS()", WHERE)); IPosition blc1(2,0,0); IPosition trc1(2,nx_p,ny_p); IPosition inc1(2, 1); /* Compute R10 = I_D*B10, R11 = I_D*B11, R12 = I_D*B12 * Compute R20 = I_D*B20, R21 = I_D*B21, R22 = I_D*B22 * ... depending on the number of scales chosen. */ /* I_D * (PSF * scale) -> matR_p [nx_p,ny_p,ntaylor,nscales] */ for (Int taylor=0; taylor coeffs = (matCoeffs_p[IND2(taylor1,scale)])(blc,trc); coeffs = 0.0; for(Int taylor2=0;taylor2 rhs = (matR_p[IND2(taylor2,scale)])(blc,trc); coeffs = coeffs + ((Float)(invMatA_p[scale])(taylor1,taylor2))* rhs; } } /* Solve for the coefficients, one scale at at time*/ /* for(Int taylor1=0;taylor1 work = ( vecWork_p[scale] )(blc,trc); work = 0.0; for(Int taylor1=0;taylor1 coeffs1 = (matCoeffs_p[IND2(taylor1,scale)])(blc,trc); Matrix resid = (matR_p[IND2(taylor1,scale)])(blc,trc); /* work = work + (Float)2.0 * coeffs1 * resid; for(Int taylor2=0;taylor2 coeffs2 = (matCoeffs_p[IND2(taylor2,scale)])(blc,trc); work = work - (Float)((matA_p[scale])(taylor1,taylor2)) * coeffs1 * coeffs2; } */ work = work + coeffs1 * resid; } findMaxAbsMask(vecWork_p[scale],vecScaleMasks_p[scale],maxScaleVal_p[scale],maxScalePos_p[scale]); /* vecWork_p[scale] = 0.0; for(Int taylor1=0;taylor1 ttWork_p((matR_p[IND2(0,0)]).shape()); ttWork_p = 0.0; for(Int taylor1=0;taylor1 ttWork_p((matR_p[IND2(0,0)]).shape()); ttWork_p = 0.0; for(Int taylor1=0;taylor1 ttWork_p((matR_p[IND2(0,0)]).shape()); ttWork_p = 0.0; for(Int taylor1=0;taylor1 coeffs, IPosition blc, IPosition trc, IPosition blcPsf, IPosition trcPsf) { for(Int taylor1=0;taylor1 residSub = (matR_p[IND2(taylor1,scale)])(blc,trc); for(Int taylor2=0;taylor2 smoothSub = (cubeA_p[IND4(taylor1,taylor2,scale,maxscaleindex_p)])(blcPsf,trcPsf); residSub -= smoothSub * loopgain * coeffs[taylor2]; // residSub = residSub - smoothSub * loopgain * (matCoeffs_p[IND2(taylor2,maxscaleindex_p)])(globalmaxpos_p); } } // return 0; }/* end of updateRHS */ /*************************************** * Update the model images and the convolved residuals TODO : The current assumption is that only one scale is chosen at a time, However the chi-sq derivative can be computed across scales too and the update could be all scales at once for the 'best' location. ****************************************/ Int MultiTermMatrixCleaner::updateModelAndRHS(Float loopgain) { /* Max support size for all updates is the full image size */ // blc, trc :model image -> needs to be centred on the component location // blcPsf : psf or scale-blob -> centred on the psf image center (peak). ///// gip = IPosition(2,nx_p,ny_p); //IPosition support(2,nx_p,ny_p); // OLD //IPosition psfpeak(itsPositionPeakPsf); /* The update region. */ //IPosition inc(2,1,1); //IPosition blc(globalmaxpos_p - support/2); //IPosition trc(globalmaxpos_p + support/2 - IPosition(2,1,1)); //LCBox::verify(blc, trc, inc, gip); /* Shifted region, with the psf at the globalmaxpos_p. */ //IPosition blcPsf(blc + psfpeak - globalmaxpos_p); // OLD //IPosition trcPsf(trc + psfpeak - globalmaxpos_p); // OLD ///LCBox::verify(blcPsf, trcPsf, inc, gip); // OLD /* The update region. */ /////IPosition inc(2,1,1); /////IPosition blc(globalmaxpos_p - psfsupport_p/2); ///// IPosition trc(globalmaxpos_p + psfsupport_p/2 - IPosition(2,1,1)); ///// LCBox::verify(blc, trc, inc, gip); /* Shifted region, with the psf at the globalmaxpos_p. */ ///// IPosition blcPsf(blc + psfpeak_p - globalmaxpos_p); // OLD ///// IPosition trcPsf(trc + psfpeak_p - globalmaxpos_p); // OLD ///// LCBox::verify(blcPsf, trcPsf, inc, psfsupport_p); // NEW /* Reconcile box sizes/locations with the image size */ ///// makeBoxesSameSize(blc,trc,blcPsf,trcPsf); //buildImagePatches(); //UUU /* cout << "Source location : " << globalmaxpos_p << endl; cout << "region around peak residual : " << blc << trc << endl; cout << "around the PSF peak : " << blcPsf << trcPsf << endl; cout << "around the Scale blob : " << blcScale << trcScale << endl; */ /* Update the model images */ /// Matrix scaleSub = (vecScales_p[maxscaleindex_p])(blcPsf,trcPsf); // OLD /// Matrix scaleSub = (vecScales_p[maxscaleindex_p])(blcScale, trcScale); // NEW Matrix scaleSub = (vecScales_p[maxscaleindex_p])(blcPsf_p, trcPsf_p); // NEWER (same size as psf) for(Int taylor=0;taylor modelSub = (vecModel_p[taylor])(blc_p,trc_p); modelSub += scaleSub * loopgain * (matCoeffs_p[IND2(taylor,maxscaleindex_p)])(globalmaxpos_p); } /* Update the convolved residuals */ Vector coeffs(ntaylor_p); for(Int taylor=0;taylor1 && inputgain_p<=(Float)0.0) { if (globalmaxval_p < prev_max_p) loopgain = loopgain * 1.5; else loopgain = loopgain / 1.5; loopgain = MIN((1-stopfraction_p),loopgain); loopgain = MIN((Float)0.6,loopgain); /* detect divergence by approximately 10 consecutive increases in maxval */ if(loopgain < (Float)0.01) { LogIO os(LogOrigin("MultiTermMatrixCleaner", "mtclean()", WHERE)); os << "Not converging any more. May be diverging. Stopping minor cycles at iteration " << totalIters_p << ". Peak residual " << fabs(rmaxval) << LogIO::POST; convergedflag=-1; } /* Stop if there is divergence : 200% increase from the current minimum value */ if( fabs( (min_max_p-globalmaxval_p)/min_max_p ) > (Float)2.0 ) { LogIO os(LogOrigin("MultiTermMatrixCleaner", "mtclean()", WHERE)); os << "Diverging.... Stopping minor cycles at iteration " << totalIters_p << ". Peak residual " << fabs(rmaxval) << " Max: " << globalmaxval_p << LogIO::POST; convergedflag=-1; } // Stop if the maxval has changed by less than 5% in 5 iterations // --- this is similar to saying less than 1% change per iteration.... same as a loopgain < 0.01 // if( abs(prev5_max - globalmaxval_p) < 0.01*abs(prev5_max) ) // { // os << "Not converging any more. Flattening out. Stopping minor cycles at iteration " << totalIters_p << ". Peak residual " << fabs(rmaxval) << LogIO::POST; // convergedflag=-1; // } }// end of if(itercount_p>1) /* Store current max value - to use in the next iteration */ prev_max_p = globalmaxval_p; // if(itercount_p%5 == 0) // prev5_max=globalmaxval_p; min_max_p = MIN(min_max_p,abs(globalmaxval_p)); /* Stop, if there are negatives on the largest scale in the Io image */ //if(nscales_p>1 && maxscaleindex_p == nscales_p-2) // if((*matCoeffs_p[IND2(0,maxscaleindex_p)]).getAt(globalmaxpos_p) < 0.0) // {converged = false;break;} /* Detect divergence, and signal it.... */ // TODO /* Print out coefficients for a few iterations */ if(convergedflag==0) { if(fluxlimit==-1) { fluxlimit = rmaxval * stopfraction_p; // os << "Peak convolved residual : " << rmaxval << " Minor cycle stopping threshold : " << itsThreshold.getValue("Jy") << LogIO::POST; LogIO os(LogOrigin("MultiTermMatrixCleaner", "mtclean()", WHERE)); os << "Peak convolved residual" ; if( ! itsMask.null() ){os << " (within mask) ";} os << " : " << rmaxval; if( fluxlimit > 0.0 ){ os << " : Minor cycle stopping threshold : " << fluxlimit;} os << LogIO::POST; } else { // if(1) if( totalIters_p==maxniter_p || (adbg==(Bool)true) || maxniter_p < (int)5 || (totalIters_p%(Int)20==0) ) { os << "[" << totalIters_p << "] Res: " << rmaxval << " Max: " << globalmaxval_p; os << " Gain: " << loopgain; //// os << "[" << totalIters_p << "] Res: " << rmaxval; //os << "[" << totalIters_p << "] Max: " << globalmaxval_p; os << " Pos: " << globalmaxpos_p << " Scale: " << scaleSizes_p[maxscaleindex_p]; os << " Coeffs: "; for(Int taylor=0;taylor& themat) { TabularCoordinate tab1(0, 1.0, 0, String("deg"), String("axis1")); TabularCoordinate tab2(0, 1.0, 0, String("deg"), String("axis2")); CoordinateSystem csys; csys.addCoordinate(tab1); csys.addCoordinate(tab2); PagedImage limage(themat.shape(), csys, imagename); limage.put(themat); //return value does not seemed to be used so will make compiler happy return 1; } /* Compute principal solution in-place on the list of residual images ( vecDirty ) -- Call MTMC::setresidual() repeatedly to fill in final residuals before computing the principal solution. This does the same as solveMatrixEquation(), but stores the results in-place in the residual images */ Bool MultiTermMatrixCleaner::computeprincipalsolution() { LogIO os(LogOrigin("MultiTermMatrixCleaner", "computeprincipalsolution()", WHERE)); os << "MTMC :: Computing principal solution on residuals" << LogIO::POST; /// If this is being called with niter=0, the Hessian won't exist. So, make it. if( doneCONV_p == false ) { if( computeHessianPeak() == -2 ) return false; } AlwaysAssert((vecDirty_p.nelements()>0), AipsError); /* Solve for the coefficients at the delta-function scale*/ for(Int taylor1=0;taylor1