Line data Source code
1 : //# WBCleanImageSkyModel.cc: Implementation of WBCleanImageSkyModel class
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library 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 Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: aips2-request@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: WBCleanImageSkyModel.cc 13615 2010-12-20 14:04:00 UrvashiRV$
27 : //# v2.6 : Added psf-patch support to reduce memory footprint.
28 :
29 : #include <casacore/casa/Arrays/ArrayMath.h>
30 : #include <synthesis/MeasurementComponents/WBCleanImageSkyModel.h>
31 : #include <synthesis/MeasurementEquations/CubeSkyEquation.h>
32 : #include <casacore/casa/OS/File.h>
33 : #include <synthesis/MeasurementEquations/SkyEquation.h>
34 : #include <synthesis/TransformMachines/StokesImageUtil.h>
35 : #include <synthesis/MeasurementEquations/LatticeModel.h>
36 : #include <synthesis/MeasurementEquations/LatConvEquation.h>
37 : #include <casacore/casa/Exceptions/Error.h>
38 : #include <casacore/casa/BasicSL/String.h>
39 : #include <casacore/casa/Utilities/Assert.h>
40 :
41 : #include <casacore/images/Images/PagedImage.h>
42 : #include <casacore/images/Images/SubImage.h>
43 : #include <casacore/images/Regions/ImageRegion.h>
44 : #include <casacore/images/Regions/RegionManager.h>
45 :
46 : #include <casacore/images/Regions/WCBox.h>
47 :
48 : #include <casacore/measures/Measures/Quality.h>
49 : #include <casacore/coordinates/Coordinates/QualityCoordinate.h>
50 : #include <casacore/images/Images/ImageUtilities.h>
51 :
52 : #include <casacore/scimath/Mathematics/MatrixMathLA.h>
53 :
54 : #include <msvis/MSVis/VisSet.h>
55 : #include <msvis/MSVis/VisSetUtil.h>
56 :
57 : #include <casacore/ms/MeasurementSets/MSColumns.h>
58 :
59 : #include <sstream>
60 :
61 : #include <casacore/casa/Logging/LogMessage.h>
62 : #include <casacore/casa/Logging/LogSink.h>
63 :
64 : #include <casacore/casa/OS/HostInfo.h>
65 :
66 :
67 : using namespace casacore;
68 : namespace casa { //# NAMESPACE CASA - BEGIN
69 : #define TMR(a) "[User: " << a.user() << "] [System: " << a.system() << "] [Real: " << a.real() << "]"
70 :
71 : #define MIN(a,b) ((a)<=(b) ? (a) : (b))
72 : #define MAX(a,b) ((a)>=(b) ? (a) : (b))
73 :
74 : /*************************************
75 : * Constructor
76 : *************************************/
77 0 : WBCleanImageSkyModel::WBCleanImageSkyModel()
78 : {
79 0 : initVars();
80 0 : nscales_p=4;
81 0 : ntaylor_p=2;
82 0 : refFrequency_p=1.42e+09;
83 0 : scaleSizes_p.resize(0);
84 0 : };
85 0 : WBCleanImageSkyModel::WBCleanImageSkyModel(const Int ntaylor,const Int nscales,const Double reffreq)
86 : {
87 0 : initVars();
88 0 : nscales_p=nscales;
89 0 : ntaylor_p=ntaylor;
90 0 : refFrequency_p=reffreq;
91 0 : scaleSizes_p.resize(0);
92 0 : };
93 0 : WBCleanImageSkyModel::WBCleanImageSkyModel(const Int ntaylor,const Vector<Float>& userScaleSizes,const Double reffreq)
94 : {
95 0 : initVars();
96 0 : if(userScaleSizes.nelements()==0) os << "No scales set !" << LogIO::WARN;
97 0 : if(userScaleSizes[0]!=0.0)
98 : {
99 0 : nscales_p=userScaleSizes.nelements()+1;
100 0 : scaleSizes_p.resize(nscales_p);
101 0 : for(Int i=1;i<nscales_p;i++) scaleSizes_p[i] = userScaleSizes[i-1];
102 0 : scaleSizes_p[0]=0.0;
103 : }
104 : else
105 : {
106 0 : nscales_p=userScaleSizes.nelements();
107 0 : scaleSizes_p.resize(nscales_p);
108 0 : for(Int i=0;i<nscales_p;i++) scaleSizes_p[i] = userScaleSizes[i];
109 : }
110 0 : ntaylor_p=ntaylor;
111 0 : refFrequency_p=reffreq;
112 0 : };
113 :
114 0 : void WBCleanImageSkyModel::initVars()
115 : {
116 0 : adbg=0;
117 0 : ddbg=1; // output per iteration
118 0 : tdbg=0;
119 :
120 0 : modified_p=true;
121 0 : memoryMB_p = Double(HostInfo::memoryTotal(true)/1024)/(2.0);
122 0 : donePSF_p=false;
123 0 : doneMTMCinit_p=false;
124 :
125 0 : numbermajorcycles_p=0;
126 0 : nfields_p=1;
127 0 : lc_p.resize(0);
128 :
129 0 : os = LogIO(LogOrigin("WBCleanImageSkyModel","solve"));
130 :
131 0 : setAlgorithm("MSMFS");
132 :
133 0 : }
134 :
135 : /*************************************
136 : * Destructor
137 : *************************************/
138 0 : WBCleanImageSkyModel::~WBCleanImageSkyModel()
139 : {
140 0 : lc_p.resize(0);
141 : //cout << "WBCleanImageSkyModel destructor " << endl;
142 :
143 : /*
144 : if(nmodels_p > numberOfModels())
145 : {
146 : resizeWorkArrays(numberOfModels());
147 : nmodels_p = numberOfModels();
148 : }
149 : */
150 :
151 0 : };
152 :
153 : /*************************************
154 : * Solver
155 : *************************************/
156 0 : Bool WBCleanImageSkyModel::solve(SkyEquation& se)
157 : {
158 0 : os << "MSMFS algorithm (v2.6) with " << ntaylor_p << " Taylor coefficients and Reference Frequency of " << refFrequency_p << " Hz" << LogIO::POST;
159 0 : Int stopflag=0;
160 0 : Int nchan=0,npol=0;
161 :
162 : /* Gather shape information */
163 0 : nmodels_p = numberOfModels();
164 :
165 0 : if(nmodels_p % ntaylor_p != 0)
166 : {
167 0 : os << "Incorrect number of input models " << LogIO::EXCEPTION;
168 0 : os << "NModels = N_fields x N_taylor" << LogIO::EXCEPTION;
169 0 : AlwaysAssert((nmodels_p % ntaylor_p == 0), AipsError);
170 : }
171 :
172 : /* Check supplied bandwidth-ratio and print warnings if needed */
173 0 : checkParameters();
174 :
175 : /* Calc the number of fields */
176 0 : nfields_p = nmodels_p/ntaylor_p;
177 : ///// NOTE : Code is written with loops on 'fields' to support a future implementation
178 : ///// Disable it for now, since it has not been tested.
179 : //AlwaysAssert(nfields_p==1, AipsError);
180 :
181 : //cout << "Number of fields : " << nfields_p << endl;
182 :
183 : /* Current restriction : one pol and one chan-plane */
184 0 : for(Int model=0;model<nmodels_p;model++)
185 : {
186 0 : nx = image(model).shape()(0);
187 0 : ny = image(model).shape()(1);
188 0 : npol=image(model).shape()(2);
189 0 : nchan=image(model).shape()(3);
190 0 : if(nchan > 1) os << "Cannot process more than one output channel" << LogIO::EXCEPTION;
191 0 : if(npol > 1) os << "Cannot process more than one output polarization" << LogIO::EXCEPTION;
192 0 : AlwaysAssert((nchan==1), AipsError);
193 0 : AlwaysAssert((npol==1), AipsError);
194 : }
195 :
196 : //------------------------------- For 'active' ---------------------------------------------------------------///
197 : /* Calculate the initial residual image for all models. */
198 0 : if( se.isNewFTM() == false )
199 : {
200 0 : if(!donePSF_p)
201 : {
202 0 : os << "Calculating initial residual images..." << LogIO::POST;
203 0 : solveResiduals(se,(numberIterations()<1)?true:False);
204 : }
205 : else
206 : {
207 : /*
208 : if(numbermajorcycles_p>0)
209 : {
210 : os << "RE-Calculating residual images because previous residuals have been modified in-place during restoration to be 'coefficient residuals'." << LogIO::POST;
211 : solveResiduals(se,(numberIterations()<1)?true:False);
212 : }
213 : */
214 : }
215 : }
216 : //------------------------------- For 'active' ---------------------------------------------------------------///
217 :
218 : /* Create the Point Spread Functions */
219 0 : if(!donePSF_p)
220 : {
221 : /* Resize the work arrays to calculate extra PSFs */
222 0 : Int original_nmodels = nmodels_p;
223 0 : nmodels_p = original_nmodels + nfields_p * (ntaylor_p - 1);
224 0 : resizeWorkArrays(nmodels_p);
225 :
226 : try
227 : {
228 : /* Make the 2N-1 PSFs */
229 0 : os << "Calculating spectral PSFs..." << LogIO::POST;
230 0 : makeSpectralPSFs(se, numberIterations()<0?true:False);
231 : }
232 0 : catch(AipsError &x)
233 : {
234 : /* Resize the work arrays to normal size - the destructors use 'nmodels_p' on other lists */
235 0 : nmodels_p = original_nmodels;
236 0 : resizeWorkArrays(nmodels_p);
237 0 : os << "Could not make PSFs. Please check image co-ordinate system : " << x.getMesg() << LogIO::EXCEPTION;
238 : }
239 :
240 0 : if(adbg) cout << "Shape of lc_p : " << lc_p.nelements() << endl;
241 : /* Initialize MTMC, allocate memory, and send in all 2N-1 psfs */
242 0 : if(lc_p.nelements()==0 && numberIterations()>=0)
243 : {
244 0 : lc_p.resize(nfields_p);
245 0 : Bool state=true;
246 : /* Initialize the MultiTermMatrixCleaners */
247 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++)
248 : {
249 0 : lc_p[thismodel].setscales(scaleSizes_p);
250 0 : lc_p[thismodel].setntaylorterms(ntaylor_p);
251 0 : nx = image(thismodel).shape()(0);
252 0 : ny = image(thismodel).shape()(1);
253 0 : state &= lc_p[thismodel].initialise(nx,ny); // allocates memory once....
254 : }
255 0 : if( !state ) // initialise will return false if there is any internal inconsistency with settings so far.
256 : {
257 0 : lc_p.resize(0);
258 0 : nmodels_p = original_nmodels;
259 0 : resizeWorkArrays(nmodels_p);
260 0 : os << LogIO::SEVERE << "Could not initialize MS-MFS minor cycle" << LogIO::EXCEPTION;
261 0 : return false; // redundant
262 : }
263 :
264 : /* Send all 2N-1 PSFs into the MultiTermLatticeCleaner */
265 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++)
266 : {
267 0 : for (Int order=0;order<2*ntaylor_p-1;order++)
268 : {
269 : // This should be doing a reference only. Make sure of this.
270 0 : Matrix<Float> tempMat;
271 0 : Array<Float> tempArr;
272 0 : (PSF(getModelIndex(thismodel,order))).get(tempArr,true);
273 0 : tempMat.reference(tempArr);
274 :
275 0 : lc_p[thismodel].setpsf( order , tempMat );
276 : }
277 : }
278 0 : doneMTMCinit_p = true;
279 : }
280 :
281 : /* Resize the work arrays to normal size - for residual comps, etc. */
282 0 : nmodels_p = original_nmodels;
283 0 : resizeWorkArrays(nmodels_p);
284 : ///// TODO : Make sure this releases memory as it is supposed to.
285 :
286 0 : donePSF_p=true;
287 : }
288 :
289 :
290 : //------------------------------ For new FTMs --------------------------------------------------------------//
291 : ///// Consider doing lc_p.setmodel and getmodel instead of dividing/multiplying the avgPB in NewMTFT::initializeToVis
292 0 : if( se.isNewFTM() == true )
293 : {
294 : /* Calculate the initial residual image for all models. */
295 0 : if( numbermajorcycles_p==0 )
296 : {
297 0 : os << "Calculating initial residual images..." << LogIO::POST;
298 0 : solveResiduals(se,(numberIterations()<1)?true:False);
299 : }
300 :
301 : }
302 : //------------------------------- For new FTMs -------------------------------------------------------------//
303 :
304 : /* Return if niter=0 */
305 : /* Check if this is an interactive-clean run, or if niter=0 */
306 0 : if(adbg) cout << "NumberIterations - before any cycles: " << numberIterations() << endl;
307 0 : if(numberIterations() < 1)
308 : {
309 0 : return true;
310 : }
311 :
312 : /* Check that lc_p's have been initialized by now.. */
313 0 : if(doneMTMCinit_p == false)
314 : {
315 0 : os << LogIO::SEVERE << "MultiTermMatrixCleaners are un-initialized, perhaps because of a previous im.clean(niter=-1) call. Please close imager, re-open it, and run with niter>=0" << LogIO::POST;
316 : }
317 :
318 : /* Set up the Mask image */
319 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++)
320 : {
321 0 : if(hasMask(getModelIndex(thismodel,0)))
322 : {
323 0 : if(adbg) os << "Sending in the mask for lc_p : " << thismodel << LogIO::POST;
324 :
325 0 : Matrix<Float> tempMat;
326 0 : Array<Float> tempArr;
327 0 : (mask(getModelIndex(thismodel,0))).get(tempArr,true);
328 0 : tempMat.reference(tempArr);
329 :
330 0 : lc_p[thismodel].setmask( tempMat );
331 : }
332 : }
333 :
334 : /******************* START MAJOR CYCLE LOOP *****************/
335 : /* Logic for number of iterations in the minor-cycle vs major cycle vs total,
336 : how they relate to convergence thresholds, and how they change with
337 : interactive vs non-interactive use (user specified total niter, vs niters per
338 : major cycle...) is a bit of a mess. Needs cleanup. Right now, hard-coded for
339 : nfields=1 */
340 0 : previous_maxresidual_p=1e+10;
341 0 : Int index=0;
342 0 : Float fractionOfPsf=0.1;
343 0 : Vector<Int> iterationcount(nfields_p); iterationcount=0;
344 0 : Vector<Int> moreiterations(nfields_p); moreiterations=0;
345 0 : Vector<Int> thiscycleniter(nfields_p); thiscycleniter=0;
346 0 : for(Int itercountmaj=0;itercountmaj<1000;itercountmaj++)
347 : {
348 0 : numbermajorcycles_p ++;
349 0 : os << "**** Major Cycle " << numbermajorcycles_p << LogIO::POST;
350 0 : thiscycleniter=0;
351 : /* Compute stopping threshold for this major cycle */
352 0 : stopflag = static_cast<casacore::Int>(computeFluxLimit(fractionOfPsf));
353 : /* If the peak residual is already less than the user-threshold, stop */
354 0 : if(stopflag==1) break;
355 : /* If we detect divergence across major cycles, stop */
356 0 : if(stopflag==-1) break;
357 :
358 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++) // For now, nfields_p=1 always.
359 : {
360 :
361 0 : if( !isSolveable(getModelIndex(thismodel,0)) )
362 : {
363 : // This field is not to be cleaned in this set of minor-cycle iterations
364 0 : continue;
365 : }
366 :
367 : /* Number of iterations left to do */
368 0 : moreiterations[thismodel] = numberIterations() - iterationcount[thismodel];
369 :
370 : /* If all iterations are done for this run, stop - for all fields*/
371 0 : if(moreiterations[thismodel] <=0 ) {stopflag=-1;break;}
372 :
373 : /* Send in the current model and residual */
374 0 : for (Int order=0;order<ntaylor_p;order++)
375 : {
376 0 : index = getModelIndex(thismodel,order);
377 :
378 0 : Matrix<Float> tempMat;
379 0 : Array<Float> tempArr;
380 :
381 0 : (residual(index)).get(tempArr,true);
382 0 : tempMat.reference(tempArr);
383 0 : lc_p[thismodel].setresidual(order,tempMat);
384 :
385 0 : (image(index)).get(tempArr,true);
386 0 : tempMat.reference(tempArr);
387 0 : lc_p[thismodel].setmodel(order,tempMat);
388 : }
389 :
390 : /* Deconvolve */
391 : /* Return value is the number of minor-cycle iterations done */
392 0 : os << "Starting Minor Cycle iterations for field : " << thismodel << LogIO::POST;
393 0 : thiscycleniter[thismodel] = lc_p[thismodel].mtclean(moreiterations[thismodel], fractionOfPsf, gain(), threshold());
394 :
395 : /* A signal for a singular Hessian : stop */
396 0 : if(thiscycleniter[thismodel]==-2) { stopflag=-2; break;}
397 :
398 : /* A signal for convergence with no iterations */
399 : /* One field may have converged, while others go on... so 'continue' */
400 : // if(thiscycleniter[thismodel]==0) { stopflag=1; break; }
401 0 : if(thiscycleniter[thismodel]==0) { stopflag=1; continue; }
402 :
403 : ///* A signal for divergence. Save current model and stop (force a major cycle). */
404 : //if(thiscycleniter==-1) { stopflag=1; }
405 :
406 : /* Increment the minor-cycle iteration counter */
407 0 : iterationcount[thismodel] += thiscycleniter[thismodel];
408 :
409 : /* Get out the updated model */
410 0 : for (Int order=0;order<ntaylor_p;order++)
411 : {
412 0 : index = getModelIndex(thismodel,order);
413 0 : Matrix<Float> tempMod;
414 0 : lc_p[thismodel].getmodel(order,tempMod);
415 0 : image(index).put(tempMod);
416 : }
417 :
418 : }// end of model loop
419 :
420 0 : if(adbg) cout << "end of major cycle : " << itercountmaj << " -> iterationcount : " << iterationcount << " thiscycleniter : " << thiscycleniter << " stopflag : " << stopflag << endl;
421 :
422 : /* Exit without further ado if MTMC cannot invert matrices */
423 0 : if(stopflag == -2)
424 : {
425 0 : os << "Cannot invert Multi-Term Hessian matrix. Please check the reference-frequency and ensure that the number of frequency-channels in the selected data >= nterms" << LogIO::WARN << LogIO::POST;
426 0 : break;
427 : }
428 :
429 : /* If reached 1000 major cycles - assume something is wrong */
430 0 : if(itercountmaj==999) os << " Reached the allowed maximum of 1000 major cycles " << LogIO::POST;
431 :
432 : /* Do the prediction and residual computation for all models. */
433 : /* Exit if we're already at the user-specified flux threshold, or reached numberIterations() */
434 0 : if( abs(stopflag)==1 || max(iterationcount) >= numberIterations() || itercountmaj==999)
435 : {
436 0 : os << "Calculating final residual images..." << LogIO::POST;
437 : /* Call 'solveResiduals' with modelToMS = true to write the model to the MS */
438 0 : solveResiduals(se,true);
439 0 : break;
440 : }
441 : else
442 : {
443 0 : os << "Calculating new residual images..." << LogIO::POST;
444 0 : solveResiduals(se);
445 : }
446 :
447 : /*
448 : if( se.isNewFTM() == true )
449 : {
450 : // The model will get PB-corrected in-place before prediction.
451 : // This needs to be reset to what the preceeding minor cycle got,
452 : // for incremental additions in the next cycle.
453 : saveCurrentModels();
454 : }
455 : */
456 :
457 : }
458 : /******************* END MAJOR CYCLE LOOP *****************/
459 :
460 : /* Compute and write alpha,beta results to disk */
461 : ///writeResultsToDisk();
462 : // calculateCoeffResiduals();
463 :
464 : /* stopflag=1 -> stopped because the user-threshold was reached */
465 : /* stopflag=-1 -> stopped because number of iterations was reached */
466 : /* stopflag=-2 -> stopped because of singular Hessian */
467 : /* stopflag=0 -> reached maximum number of major-cycle iterations !! */
468 0 : if(stopflag>0) return(true);
469 0 : else return(false);
470 : } // END OF SOLVE
471 :
472 :
473 0 : void WBCleanImageSkyModel::saveCurrentModels()
474 : {
475 :
476 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++)
477 : {
478 : /* Get out the updated model */
479 0 : for (Int order=0;order<ntaylor_p;order++)
480 : {
481 0 : Int index = getModelIndex(thismodel,order);
482 0 : Matrix<Float> tempMod;
483 0 : lc_p[thismodel].getmodel(order,tempMod);
484 0 : image(index).put(tempMod);
485 : }
486 : }// end of model loop
487 :
488 0 : }// end of saveCurrentModels
489 :
490 :
491 : /* Calculate stopping threshold for the current set of minor-cycle iterations */
492 : /* Note : The stopping threshold is computed from the residual image.
493 : However, MTMC checks on the peak of (residual * psf * scale_0).
494 : These values can differ slightly.
495 : TODO : Perhaps move this function back into MTMC.
496 : (It was brought out to conform to the other devonvolvers..)
497 : */
498 0 : Float WBCleanImageSkyModel::computeFluxLimit(Float &fractionOfPsf)
499 : {
500 0 : LogIO os(LogOrigin("WBCleanImageSkyModel", "computeFluxLimit", WHERE));
501 0 : Float maxres=0.0,maxval=0.0,minval=0.0;
502 0 : Vector<Float> fmaxres(nfields_p); fmaxres=0.0;
503 :
504 : /* Measure the peak residual across all fields */
505 0 : for(Int field=0;field<nfields_p;field++)
506 : {
507 0 : Int index = getModelIndex(field,0);
508 0 : Array<Float> tempArr;
509 0 : (residual(index)).get(tempArr,true);
510 0 : IPosition maxpos(tempArr.shape()),minpos(tempArr.shape());
511 0 : minMax(minval,maxval, minpos, maxpos,tempArr);
512 0 : fmaxres[field]=maxval;
513 : }
514 :
515 : /* Pick the peak residual across all fields */
516 0 : maxres = max(fmaxres);
517 0 : if(adbg) cout << "Peak Residual across fields (over all pixels) : " << maxres << endl;
518 :
519 : /* If we've already converged, return */
520 0 : if(maxres < threshold())
521 : {
522 0 : os << "Peak residual : " << maxres << " is lower than the user-specified stopping threshold : " << threshold() << LogIO::POST;
523 0 : return 1;
524 : }
525 :
526 : /* If we detect divergence across major cycles, warn or STOP */
527 0 : if(fabs( ((maxres - previous_maxresidual_p)/previous_maxresidual_p ) > 10.0 ))
528 : {
529 0 : os << "Peak residual : " << maxres << " has increased by more than a factor of 10 across major cycles. Could be diverging. Stopping" << LogIO::POST;
530 0 : return -1;
531 : }
532 0 : if(fabs( ((maxres - previous_maxresidual_p)/previous_maxresidual_p ) > 2.0 ))
533 : {
534 0 : os << "Peak residual : " << maxres << " has increased across major cycles. Could be diverging, but continuing..." << LogIO::POST;
535 : }
536 0 : previous_maxresidual_p = maxres;
537 :
538 : /* Find PSF sidelobe level */
539 0 : Float maxpsfside=0.0;
540 0 : for(uInt field=0;static_cast<Int>(field)<nfields_p;field++)
541 : {
542 0 : Int index = getModelIndex(field,0);
543 : /* abs(min of the PSF) will be treated as the max sidelobe level */
544 0 : Array<Float> tempArr;
545 0 : (PSF(index)).get(tempArr,true);
546 0 : IPosition maxpos(tempArr.shape()),minpos(tempArr.shape());
547 0 : minMax(minval,maxval, minpos, maxpos,tempArr);
548 0 : maxpsfside = max(maxpsfside, abs(minval));
549 : }
550 :
551 0 : fractionOfPsf = min(cycleMaxPsfFraction_p, cycleFactor_p * maxpsfside);
552 0 : if(fractionOfPsf>0.8) fractionOfPsf=0.8;
553 : // cyclethreshold = max(threshold(), fractionOfPsf * maxres);
554 :
555 : // if(adbg)
556 : {
557 0 : os << "Peak Residual (all pixels) : " << maxres << " User Threshold : " << threshold() << " Max PSF Sidelobe : " << abs(minval) << " User maxPsfFraction : " << cycleMaxPsfFraction_p << " User cyclefactor : " << cycleFactor_p << " fractionOfPsf = min(maxPsfFraction, PSFsidelobe x cyclefactor) : " << fractionOfPsf << LogIO::POST;
558 : // os << "Stopping threshold for this major cycle min(user threshold , fractionOfPsf x Max Residual) : " << cyclethreshold << endl;
559 : }
560 :
561 0 : return 0;
562 : }
563 :
564 : /***********************************************************************/
565 0 : Bool WBCleanImageSkyModel::calculateAlphaBeta(const Vector<String> &restoredNames,
566 : const Vector<String> &residualNames)
567 : {
568 0 : LogIO os(LogOrigin("WBCleanImageSkyModel", "calculateAlphaBeta", WHERE));
569 : //UNUSED: Int index=0;
570 0 : Bool writeerror=true;
571 :
572 :
573 0 : for(Int field=0;field<nfields_p;field++)
574 : {
575 0 : Int baseindex = getModelIndex(field,0);
576 0 : String alphaname,betaname, alphaerrorname;
577 0 : if( ( (restoredNames[baseindex]).substr( (restoredNames[baseindex]).length()-3 , 3 ) ).matches("tt0") )
578 : {
579 0 : alphaname = (restoredNames[baseindex]).substr(0,(restoredNames[baseindex]).length()-3) + "alpha";
580 0 : betaname = (restoredNames[baseindex]).substr(0,(restoredNames[baseindex]).length()-3) + "beta";
581 0 : if(writeerror) alphaerrorname = alphaname+".error";
582 : }
583 : else
584 : {
585 0 : alphaname = (restoredNames[baseindex]) + String(".alpha");
586 0 : betaname = (restoredNames[baseindex]) + String(".beta");
587 : }
588 :
589 : /* Create empty alpha image, and alpha error image */
590 0 : PagedImage<Float> imalpha(image(baseindex).shape(),image(baseindex).coordinates(),alphaname);
591 0 : imalpha.set(0.0);
592 :
593 : /* Open restored images */
594 0 : PagedImage<Float> imtaylor0(restoredNames[getModelIndex(field,0)]);
595 0 : PagedImage<Float> imtaylor1(restoredNames[getModelIndex(field,1)]);
596 :
597 : /* Open first residual image */
598 0 : PagedImage<Float> residual0(residualNames[getModelIndex(field,0)]);
599 :
600 : /* Create a mask - make this adapt to the signal-to-noise */
601 0 : LatticeExprNode leMaxRes=max(residual0);
602 0 : Float maxres = leMaxRes.getFloat();
603 : // Threshold is either 10% of the peak residual (psf sidelobe level) or
604 : // user threshold, if deconvolution has gone that deep.
605 0 : Float specthreshold = MAX( threshold()*5 , maxres/5.0 );
606 0 : os << "Calculating spectral parameters for Intensity > MAX(threshold*5,peakresidual/5) = " << specthreshold << " Jy/beam" << LogIO::POST;
607 0 : LatticeExpr<Float> mask1(iif((imtaylor0)>(specthreshold),1.0,0.0));
608 0 : LatticeExpr<Float> mask0(iif((imtaylor0)>(specthreshold),0.0,1.0));
609 :
610 : /////// Calculate alpha
611 0 : LatticeExpr<Float> alphacalc( ((imtaylor1)*mask1)/((imtaylor0)+(mask0)) );
612 0 : imalpha.copyData(alphacalc);
613 :
614 : // Set the restoring beam for alpha
615 0 : ImageInfo ii = imalpha.imageInfo();
616 0 : ii.setRestoringBeam( (imtaylor0.imageInfo()).restoringBeam() );
617 0 : imalpha.setImageInfo(ii);
618 : //imalpha.setUnits(Unit("Spectral Index"));
619 0 : imalpha.table().unmarkForDelete();
620 :
621 : // Make a mask for the alpha image
622 0 : LatticeExpr<Bool> lemask(iif((imtaylor0 > specthreshold) , true, false));
623 :
624 0 : createMask(lemask, imalpha);
625 0 : os << "Written Spectral Index Image : " << alphaname << LogIO::POST;
626 :
627 :
628 : ////// Calculate error on alpha
629 0 : if(writeerror)
630 : {
631 0 : PagedImage<Float> imalphaerror(image(baseindex).shape(),image(baseindex).coordinates(),alphaerrorname);
632 0 : imalphaerror.set(0.0);
633 0 : PagedImage<Float> residual1(residualNames[getModelIndex(field,1)]);
634 :
635 0 : LatticeExpr<Float> alphacalcerror( abs(alphacalc) * sqrt( ( (residual0*mask1)/(imtaylor0+mask0) )*( (residual0*mask1)/(imtaylor0+mask0) ) + ( (residual1*mask1)/(imtaylor1+mask0) )*( (residual1*mask1)/(imtaylor1+mask0) ) ) );
636 0 : imalphaerror.copyData(alphacalcerror);
637 0 : imalphaerror.setImageInfo(ii);
638 0 : createMask(lemask, imalphaerror);
639 0 : imalphaerror.table().unmarkForDelete();
640 0 : os << "Written Spectral Index Error Image : " << alphaerrorname << LogIO::POST;
641 :
642 : // mergeDataError( imalpha, imalphaerror, alphaerrorname+".new" );
643 :
644 : }
645 :
646 : ////// Calculate beta
647 0 : if(ntaylor_p>2)
648 : {
649 0 : PagedImage<Float> imbeta(image(baseindex).shape(),image(baseindex).coordinates(),betaname);
650 0 : imbeta.set(0.0);
651 0 : PagedImage<Float> imtaylor2(restoredNames[getModelIndex(field,2)]);
652 :
653 0 : LatticeExpr<Float> betacalc( ((imtaylor2)*mask1)/((imtaylor0)+(mask0))-0.5*(imalpha)*(imalpha-1.0) );
654 0 : imbeta.copyData(betacalc);
655 0 : imbeta.setImageInfo(ii);
656 : //imbeta.setUnits(Unit("Spectral Curvature"));
657 0 : createMask(lemask, imbeta);
658 0 : imbeta.table().unmarkForDelete();
659 :
660 0 : os << "Written Spectral Curvature Image : " << betaname << LogIO::POST;
661 : }
662 :
663 : }// field loop
664 :
665 0 : return 0;
666 :
667 : }
668 : /***********************************************************************/
669 :
670 0 : Bool WBCleanImageSkyModel::createMask(LatticeExpr<Bool> &lemask, ImageInterface<Float> &outimage)
671 : {
672 0 : ImageRegion outreg = outimage.makeMask("mask0",false,true);
673 0 : LCRegion& outmask=outreg.asMask();
674 0 : outmask.copyData(lemask);
675 0 : outimage.defineRegion("mask0",outreg, RegionHandler::Masks, true);
676 0 : outimage.setDefaultMask("mask0");
677 0 : return true;
678 : }
679 :
680 :
681 : /***********************************************************************/
682 0 : Bool WBCleanImageSkyModel::calculateCoeffResiduals()
683 : {
684 0 : for(Int field=0;field<nfields_p;field++)
685 : {
686 0 : Int baseindex = getModelIndex(field,0);
687 :
688 :
689 : // Send in the final residuals
690 0 : for (Int order=0;order<ntaylor_p;order++)
691 : {
692 0 : Int index = getModelIndex(field,order);
693 0 : Matrix<Float> tempMat;
694 0 : Array<Float> tempArr;
695 0 : (residual(index)).get(tempArr,true);
696 0 : tempMat.reference(tempArr);
697 0 : lc_p[baseindex].setresidual(order,tempMat);
698 : }
699 :
700 : // Compute principal solution in-place.
701 0 : lc_p[baseindex].computeprincipalsolution();
702 :
703 : // Get the new residuals
704 0 : for (Int order=0;order<ntaylor_p;order++)
705 : {
706 0 : Int index = getModelIndex(field,order);
707 0 : Matrix<Float> tempMod;
708 0 : lc_p[baseindex].getresidual(order,tempMod);
709 0 : residual(index).put(tempMod);
710 : }
711 :
712 :
713 : /*
714 :
715 : //Apply Inverse Hessian to the residuals
716 : IPosition gip(4,image(baseindex).shape()[0],image(baseindex).shape()[1],1,1);
717 : Matrix<Double> invhessian;
718 : lc_p[field].getinvhessian(invhessian);
719 : //cout << "Inverse Hessian : " << invhessian << endl;
720 :
721 : Int tindex;
722 : LatticeExprNode len_p;
723 : PtrBlock<TempLattice<Float>* > coeffresiduals(ntaylor_p); //,smoothresiduals(ntaylor_p);
724 : for(Int taylor1=0;taylor1<ntaylor_p;taylor1++)
725 : {
726 : coeffresiduals[taylor1] = new TempLattice<Float>(gip,memoryMB_p);
727 : }
728 :
729 : //Apply the inverse Hessian to the residuals
730 : for(Int taylor1=0;taylor1<ntaylor_p;taylor1++)
731 : {
732 : len_p = LatticeExprNode(0.0);
733 : for(Int taylor2=0;taylor2<ntaylor_p;taylor2++)
734 : {
735 : tindex = getModelIndex(field,taylor2);
736 : len_p = len_p + LatticeExprNode((Float)(invhessian)(taylor1,taylor2)*(residual(tindex)));
737 : }
738 : (*coeffresiduals[taylor1]).copyData(LatticeExpr<Float>(len_p));
739 : }
740 :
741 : //Fill in the residual images with these coefficient residuals
742 : for(Int taylor=0;taylor<ntaylor_p;taylor++)
743 : {
744 : tindex = getModelIndex(field,taylor);
745 : (residual(tindex)).copyData(LatticeExpr<Float>(*coeffresiduals[taylor]));
746 : }
747 :
748 : for(uInt i=0;i<coeffresiduals.nelements();i++)
749 : {
750 : if(coeffresiduals[i]) delete coeffresiduals[i];
751 : }
752 : */
753 :
754 :
755 : }//end of field loop
756 0 : os << "Converting final residuals to 'coefficient residuals', for restoration" << LogIO::POST;
757 0 : return true;
758 : }//end of calculateCoeffResiduals
759 :
760 : /***********************************************************************/
761 : ///// Write alpha and beta to disk. Calculate from smoothed model + residuals.
762 0 : Int WBCleanImageSkyModel::writeResultsToDisk()
763 : {
764 0 : if(ntaylor_p<=1) return 0;
765 :
766 0 : os << "Output Taylor-coefficient images : " << imageNames << LogIO::POST;
767 : // if(ntaylor_p==2) os << "Calculating Spectral Index" << LogIO::POST;
768 : // if(ntaylor_p>2) os << "Calculating Spectral Index and Curvature" << LogIO::POST;
769 :
770 :
771 0 : GaussianBeam beam;
772 0 : Int index=0;
773 :
774 0 : for(Int field=0;field<nfields_p;field++)
775 : {
776 0 : PtrBlock<TempLattice<Float>* > smoothed;
777 0 : if(ntaylor_p>2) smoothed.resize(3);
778 0 : else if(ntaylor_p==2) smoothed.resize(2);
779 :
780 0 : Int baseindex = getModelIndex(field,0);
781 0 : String alphaname,betaname;
782 0 : if( ( (imageNames[baseindex]).substr( (imageNames[baseindex]).length()-3 , 3 ) ).matches("tt0") )
783 : {
784 0 : alphaname = (imageNames[baseindex]).substr(0,(imageNames[baseindex]).length()-3) + "alpha";
785 0 : betaname = (imageNames[baseindex]).substr(0,(imageNames[baseindex]).length()-3) + "beta";
786 : }
787 : else
788 : {
789 0 : alphaname = (imageNames[baseindex]) + String(".alpha");
790 0 : betaname = (imageNames[baseindex]) + String(".beta");
791 : }
792 :
793 0 : StokesImageUtil::FitGaussianPSF(PSF(baseindex), beam);
794 :
795 : /* Create empty alpha image */
796 0 : PagedImage<Float> imalpha(image(baseindex).shape(),image(baseindex).coordinates(),alphaname);
797 0 : imalpha.set(0.0);
798 :
799 : /* Apply Inverse Hessian to the residuals */
800 0 : IPosition gip(4,image(baseindex).shape()[0],image(baseindex).shape()[1],1,1);
801 0 : Matrix<Double> invhessian;
802 0 : lc_p[field].getinvhessian(invhessian);
803 : //cout << "Inverse Hessian : " << invhessian << endl;
804 :
805 : Int tindex;
806 0 : LatticeExprNode len_p;
807 0 : PtrBlock<TempLattice<Float>* > coeffresiduals(ntaylor_p); //,smoothresiduals(ntaylor_p);
808 0 : for(Int taylor1=0;taylor1<ntaylor_p;taylor1++)
809 : {
810 0 : coeffresiduals[taylor1] = new TempLattice<Float>(gip,memoryMB_p);
811 : }
812 :
813 : /* Apply the inverse Hessian to the residuals */
814 0 : for(Int taylor1=0;taylor1<ntaylor_p;taylor1++)
815 : {
816 0 : len_p = LatticeExprNode(0.0);
817 0 : for(Int taylor2=0;taylor2<ntaylor_p;taylor2++)
818 : {
819 0 : tindex = getModelIndex(field,taylor2);
820 0 : len_p = len_p + LatticeExprNode((Float)(invhessian)(taylor1,taylor2)*(residual(tindex)));
821 : }
822 0 : (*coeffresiduals[taylor1]).copyData(LatticeExpr<Float>(len_p));
823 : }
824 :
825 : /* Fill in the residual images with these coefficient residuals */
826 0 : for(Int taylor=0;taylor<ntaylor_p;taylor++)
827 : {
828 0 : tindex = getModelIndex(field,taylor);
829 0 : (residual(taylor)).copyData(LatticeExpr<Float>(*coeffresiduals[taylor]));
830 : }
831 :
832 :
833 : /* Smooth the model images and add the above coefficient residuals */
834 0 : for(uInt i=0;i<smoothed.nelements();i++)
835 : {
836 0 : smoothed[i] = new TempLattice<Float>(gip,memoryMB_p);
837 :
838 0 : index = getModelIndex(field,i);
839 0 : LatticeExpr<Float> cop(image(index));
840 0 : imalpha.copyData(cop);
841 0 : StokesImageUtil::Convolve(imalpha, beam);
842 : //cout << "Clean Beam from WBC : " << bmaj << " , " << bmin << " , " << bpa << endl;
843 : //cout << "SkyModel internally-recorded beam for index " << index << " : " << beam(index) << endl;
844 : //LatticeExpr<Float> le(imalpha);
845 0 : LatticeExpr<Float> le(imalpha+( *coeffresiduals[i] ));
846 0 : (*smoothed[i]).copyData(le);
847 : }
848 :
849 :
850 : /* Create a mask - make this adapt to the signal-to-noise */
851 0 : LatticeExprNode leMaxRes=max(residual( getModelIndex(field,0) ));
852 0 : Float maxres = leMaxRes.getFloat();
853 : // Threshold is either 10% of the peak residual (psf sidelobe level) or
854 : // user threshold, if deconvolution has gone that deep.
855 0 : Float specthreshold = MAX( threshold()*5 , maxres/5.0 );
856 0 : os << "Calculating spectral parameters for Intensity > MAX(threshold*5,peakresidual/5) = " << specthreshold << " Jy/beam" << LogIO::POST;
857 0 : LatticeExpr<Float> mask1(iif((*smoothed[0])>(specthreshold),1.0,0.0));
858 0 : LatticeExpr<Float> mask0(iif((*smoothed[0])>(specthreshold),0.0,1.0));
859 :
860 : /* Calculate alpha and beta */
861 0 : LatticeExpr<Float> alphacalc( ((*smoothed[1])*mask1)/((*smoothed[0])+(mask0)) );
862 0 : imalpha.copyData(alphacalc);
863 :
864 0 : ImageInfo ii = imalpha.imageInfo();
865 0 : ii.setRestoringBeam(beam);
866 :
867 0 : imalpha.setImageInfo(ii);
868 : //imalpha.setUnits(Unit("Spectral Index"));
869 0 : imalpha.table().unmarkForDelete();
870 0 : os << "Written Spectral Index Image : " << alphaname << LogIO::POST;
871 :
872 0 : if(ntaylor_p>2)
873 : {
874 0 : PagedImage<Float> imbeta(image(baseindex).shape(),image(baseindex).coordinates(),betaname);
875 0 : imbeta.set(0.0);
876 :
877 0 : LatticeExpr<Float> betacalc( ((*smoothed[2])*mask1)/((*smoothed[0])+(mask0))-0.5*(imalpha)*(imalpha-1.0) );
878 0 : imbeta.copyData(betacalc);
879 :
880 0 : imbeta.setImageInfo(ii);
881 : //imbeta.setUnits(Unit("Spectral Curvature"));
882 0 : imbeta.table().unmarkForDelete();
883 0 : os << "Written Spectral Curvature Image : " << betaname << LogIO::POST;
884 : }
885 :
886 : /* Print out debugging info for center pixel */
887 : /*
888 : IPosition cgip(4,512,512,0,0);
889 : IPosition cgip2(4,490,542,0,0);
890 : for(Int i=0;i<ntaylor_p;i++)
891 : {
892 : cout << "Extended : " << endl;
893 : cout << "Original residual : " << i << " : " << residual( getModelIndex(model,i) ).getAt(cgip) << endl;
894 : cout << "Smoothed residual : " << i << " : " << (*smoothresiduals[i]).getAt(cgip) << endl;
895 : cout << "Coeff residual : " << i << " : " << (*coeffresiduals[i]).getAt(cgip) << endl;
896 : cout << "Point : " << endl;
897 : cout << "Original residual : " << i << " : " << residual( getModelIndex(model,i) ).getAt(cgip2) << endl;
898 : cout << "Smoothed residual : " << i << " : " << (*smoothresiduals[i]).getAt(cgip2) << endl;
899 : cout << "Coeff residual : " << i << " : " << (*coeffresiduals[i]).getAt(cgip2) << endl;
900 : }
901 : */
902 :
903 :
904 : /* Clean up temp arrays */
905 0 : for(uInt i=0;i<smoothed.nelements();i++) if(smoothed[i]) delete smoothed[i];
906 0 : for(uInt i=0;i<coeffresiduals.nelements();i++)
907 : {
908 0 : if(coeffresiduals[i]) delete coeffresiduals[i];
909 : }
910 :
911 : }// field loop
912 0 : return 0;
913 : }
914 :
915 : /***********************************************************************/
916 : /*************************************
917 : * Make Residuals and compute the current peak
918 : *************************************/
919 0 : Bool WBCleanImageSkyModel::solveResiduals(SkyEquation& se, Bool modelToMS)
920 : {
921 0 : blankOverlappingModels();
922 0 : makeNewtonRaphsonStep(se,false,modelToMS);
923 0 : restoreOverlappingModels();
924 :
925 0 : return true;
926 : }
927 : /***********************************************************************/
928 :
929 : /*************************************
930 : * Make Residuals
931 : *************************************/
932 : // Currently - all normalized by ggS from taylor0.
933 : // SAME WITH MAKE_SPECTRAL_PSFS
934 :
935 0 : Bool WBCleanImageSkyModel::makeNewtonRaphsonStep(SkyEquation& se, Bool incremental, Bool modelToMS)
936 : {
937 0 : LogIO os(LogOrigin("WBCleanImageSkyModel", "makeNewtonRaphsonStep"));
938 0 : se.gradientsChiSquared(incremental, modelToMS);
939 :
940 0 : Int index=0,baseindex=0;
941 0 : LatticeExpr<Float> le;
942 0 : for(Int thismodel=0;thismodel<nfields_p;thismodel++)
943 : {
944 0 : baseindex = getModelIndex(thismodel,0);
945 0 : for(Int taylor=0;taylor<ntaylor_p;taylor++)
946 : {
947 : /* Normalize by the Taylor 0 weight image */
948 0 : index = getModelIndex(thismodel,taylor);
949 : //cout << "Normalizing image " << index << " with " << baseindex << endl;
950 : //cout << "Shapes : " << ggS(index).shape() << gS(baseindex).shape() << endl;
951 :
952 : // UUU
953 : // LatticeExpr<Float> le(iif(ggS(baseindex)>(0.0), -gS(index)/ggS(baseindex), 0.0));
954 :
955 : ///cout << "WBC : makeNRs : isnormalized : " << isImageNormalized() << endl;
956 :
957 0 : if (isImageNormalized()) le = LatticeExpr<Float>(gS(index));
958 0 : else le = LatticeExpr<Float>(iif(ggS(baseindex)>(0.0),
959 0 : -gS(index)/ggS(baseindex), 0.0));
960 0 : residual(index).copyData(le);
961 :
962 : //LatticeExprNode LEN = max( residual(index) );
963 : //LatticeExprNode len2 = max( ggS(baseindex) );
964 : //cout << "Max Residual : " << LEN.getFloat() << " Max ggS : " << len2.getFloat() << endl;
965 :
966 :
967 : //storeAsImg(String("Weight.")+String::toString(thismodel)+String(".")+String::toString(taylor),ggS(index));
968 : //storeAsImg(String("TstResidual.")+String::toString(thismodel)+String(".")+String::toString(taylor),residual(index));
969 : }
970 : }
971 0 : modified_p=false;
972 0 : return true;
973 : }
974 :
975 : /*************************************
976 : * Make Approx PSFs.
977 : *************************************/
978 : // The normalization ignores that done in makeSimplePSFs in the Sky Eqn
979 : // and recalculates it from gS and ggS.
980 0 : Int WBCleanImageSkyModel::makeSpectralPSFs(SkyEquation& se, Bool writeToDisk)
981 : {
982 0 : LogIO os(LogOrigin("WBCleanImageSkyModel", "makeSpectralPSFs"));
983 0 : if(!donePSF_p)
984 : {
985 : //make sure the psf images are made
986 0 : for (Int thismodel=0;thismodel<nmodels_p;thismodel++)
987 : {
988 0 : PSF(thismodel);
989 : }
990 : }
991 :
992 : // All 2N-1 psfs will get made here....
993 0 : se.makeApproxPSF(psf_p);
994 :
995 : // Normalize
996 0 : Float normfactor=1.0;
997 0 : Int index=0,baseindex=0;
998 0 : LatticeExpr<Float> le;
999 0 : for (Int thismodel=0;thismodel<nfields_p;thismodel++)
1000 : {
1001 0 : normfactor=1.0;
1002 0 : baseindex = getModelIndex(thismodel,0);
1003 0 : for(Int taylor=0;taylor<2*ntaylor_p-1;taylor++)
1004 : {
1005 : /* Normalize by the Taylor 0 weight image */
1006 0 : index = getModelIndex(thismodel,taylor);
1007 : //cout << "Normalizing PSF " << index << " with " << baseindex << endl;
1008 : //cout << "Shapes : " << ggS(index).shape() << gS(baseindex).shape() << endl;
1009 : //le = LatticeExpr<Float>(iif(ggS(baseindex)>(0.0), gS(index)/ggS(baseindex), 0.0));
1010 0 : if (isImageNormalized()) le = LatticeExpr<Float>(gS(index));
1011 0 : else le = LatticeExpr<Float>(iif(ggS(baseindex)>(0.0),
1012 0 : gS(index)/ggS(baseindex), 0.0));
1013 0 : PSF(index).copyData(le);
1014 0 : if(taylor==0)
1015 : {
1016 0 : LatticeExprNode maxPSF=max(PSF(index));
1017 0 : normfactor = maxPSF.getFloat();
1018 0 : if(adbg) os << "Normalize PSFs for field " << thismodel << " by " << normfactor << LogIO::POST;
1019 : }
1020 0 : LatticeExpr<Float> lenorm(PSF(index)/normfactor);
1021 0 : PSF(index).copyData(lenorm);
1022 0 : LatticeExprNode maxPSF2=max(PSF(index));
1023 0 : Float maxpsf=maxPSF2.getFloat();
1024 0 : if(adbg) os << "Psf for Model " << thismodel << " and Taylor " << taylor << " has peak " << maxpsf << LogIO::POST;
1025 :
1026 0 : if(writeToDisk)
1027 : {
1028 : //need unique name as multiple processes can be running in the
1029 : //same workingdir
1030 0 : String tmpName=image_p[thismodel]->name();
1031 0 : tmpName.del(String(".model.tt0"), 0);
1032 0 : storeAsImg(tmpName+String(".TempPsf.")+String::toString(taylor),PSF(index));
1033 : }
1034 : }
1035 :
1036 : // index = getModelIndex(thismodel,0);
1037 : //beam(thismodel)=0.0;
1038 0 : if(!StokesImageUtil::FitGaussianPSF(PSF(baseindex),beam(thismodel)))
1039 0 : os << "Beam fit failed: using default" << LogIO::POST;
1040 : }
1041 0 : return 0;
1042 : }
1043 :
1044 :
1045 :
1046 : /***********************************************************************/
1047 :
1048 : /*************************************
1049 : * Store a Templattice as an image
1050 : *************************************/
1051 :
1052 0 : Int WBCleanImageSkyModel::storeAsImg(String fileName, ImageInterface<Float>& theImg)
1053 : {
1054 0 : PagedImage<Float> tmp(theImg.shape(), theImg.coordinates(), fileName);
1055 0 : LatticeExpr<Float> le(theImg);
1056 0 : tmp.copyData(le);
1057 0 : return 0;
1058 : }
1059 : /*
1060 : Int WBCleanImageSkyModel::storeTLAsImg(String fileName, TempLattice<Float> &TL, ImageInterface<Float>& theImg)
1061 : {
1062 : PagedImage<Float> tmp(TL.shape(), theImg.coordinates(), fileName);
1063 : LatticeExpr<Float> le(TL);
1064 : tmp.copyData(le);
1065 : return 0;
1066 : }
1067 :
1068 : Int WBCleanImageSkyModel::storeTLAsImg(String fileName, TempLattice<Complex> &TL, ImageInterface<Float>& theImg)
1069 : {
1070 : PagedImage<Complex> tmp(TL.shape(), theImg.coordinates(), fileName);
1071 : LatticeExpr<Complex> le(TL);
1072 : tmp.copyData(le);
1073 : return 0;
1074 : }
1075 : */
1076 :
1077 : /**************************
1078 : Resize Work Arrays to calculate extra PSFs.
1079 : (Resizing back to a shorter list must free memory correctly).
1080 : *************************/
1081 0 : Bool WBCleanImageSkyModel::resizeWorkArrays(Int length)
1082 : {
1083 0 : Int originallength = gS_p.nelements();
1084 :
1085 0 : if(length < originallength) // Clean up extra arrays
1086 : {
1087 0 : for(Int i = length; i < originallength; ++i)
1088 : {
1089 0 : if(psf_p[i]){delete psf_p[i]; psf_p[i]=0;}
1090 0 : if(image_p[i]){delete image_p[i]; image_p[i]=0;}
1091 0 : if(cimage_p[i]){delete cimage_p[i]; cimage_p[i]=0;}
1092 0 : if(gS_p[i]){delete gS_p[i]; gS_p[i]=0;}
1093 0 : if(ggS_p[i]){delete ggS_p[i]; ggS_p[i]=0;}
1094 0 : if(work_p[i]){delete work_p[i]; work_p[i]=0;}
1095 0 : if(fluxScale_p[i]){delete fluxScale_p[i]; fluxScale_p[i]=0;}
1096 : }
1097 :
1098 : }
1099 :
1100 0 : psf_p.resize(length,true);
1101 0 : image_p.resize(length,true);
1102 0 : cimage_p.resize(length,true);
1103 0 : gS_p.resize(length,true);
1104 0 : ggS_p.resize(length,true);
1105 0 : work_p.resize(length,true);
1106 0 : fluxScale_p.resize(length,true);
1107 :
1108 0 : if(length > originallength) // Add extra arrays // TODO : This part can go - I think !!!
1109 : {
1110 0 : for(Int i = originallength; i < length; ++i)
1111 : {
1112 0 : psf_p[i]=0;gS_p[i]=0;ggS_p[i]=0;cimage_p[i]=0;work_p[i]=0;fluxScale_p[i]=0;
1113 :
1114 0 : Int ind = getFieldIndex(i);
1115 : TempImage<Float>* imptr =
1116 0 : new TempImage<Float> (IPosition(image_p[ind]->ndim(),
1117 0 : image_p[ind]->shape()(0),
1118 0 : image_p[ind]->shape()(1),
1119 0 : image_p[ind]->shape()(2),
1120 0 : image_p[ind]->shape()(3)),
1121 0 : image_p[ind]->coordinates(), memoryMB_p);
1122 0 : AlwaysAssert(imptr, AipsError);
1123 0 : image_p[i] = imptr;
1124 : }
1125 : }
1126 :
1127 : ///cout << "Memory held by ImageSkyModel : " << 6*length << " float + " << 1*length << " complex images " << endl;
1128 :
1129 0 : return true;
1130 : }
1131 :
1132 : /************************************************************************************
1133 : Check some input parameters and print warnings for the user
1134 : fbw = (fmax-fmin)/fref.
1135 : if(fbw < 0.1) and nterms>2
1136 : => lever-arm may be insufficient for more than alpha.
1137 : => polynomial fit will work but alpha interpretation may not be ok.
1138 : if(ref < fmin or ref > fmax)
1139 : => polynomial fit will work, but alpha interpretation will not be right.
1140 : if(nchan==1) or fbw = 0, then ask to use only nterms=1, or choose more than one chan
1141 :
1142 : ***********************************************************************************/
1143 0 : Bool WBCleanImageSkyModel::checkParameters()
1144 : {
1145 : /* Check ntaylor_p, nrefFrequency_p with min and max freq from the image-coords */
1146 :
1147 0 : for(uInt i=0; i<image(0).coordinates().nCoordinates(); i++)
1148 : {
1149 0 : if( image(0).coordinates().type(i) == Coordinate::SPECTRAL )
1150 : {
1151 0 : SpectralCoordinate speccoord(image(0).coordinates().spectralCoordinate(i));
1152 0 : Double startfreq=0.0,startpixel=-0.5;
1153 0 : Double endfreq=0.0,endpixel=+0.5;
1154 0 : speccoord.toWorld(startfreq,startpixel);
1155 0 : speccoord.toWorld(endfreq,endpixel);
1156 0 : Float fbw = (endfreq - startfreq)/refFrequency_p;
1157 : //os << "Freq range of the mfs channel : " << startfreq << " -> " << endfreq << endl;
1158 : //cout << "Fractional bandwidth : " << fbw << endl;
1159 :
1160 0 : os << "Fractional Bandwidth : " << fbw*100 << " %." << LogIO::POST;
1161 :
1162 : /*
1163 : if(fbw < 0.1 && ntaylor_p == 2 )
1164 : os << "Fractional Bandwidth is " << fbw*100 << " %. Please check that the flux variation across the chosen frequency range (" << startfreq << " Hz to " << endfreq << " Hz) is at least twice the single-channel noise-level. If not, please use nterms=1." << LogIO::WARN << LogIO::POST;
1165 :
1166 : if(fbw < 0.1 && ntaylor_p > 2)
1167 : os << "Fractional Bandwidth is " << fbw*100 << " %. Please check that (a) the flux variation across the chosen frequency range (" << startfreq << " Hz to " << endfreq << " Hz) is at least twice the single-channel noise-level, and (b) a " << ntaylor_p << "-term Taylor-polynomial fit across this frequency range is appropriate. " << LogIO::WARN << LogIO::POST;
1168 : */
1169 0 : if(refFrequency_p < startfreq || refFrequency_p > endfreq)
1170 0 : os << "A Reference frequency of " << refFrequency_p << "Hz is outside the frequency range of the selected data (" << startfreq << " Hz to " << endfreq << " Hz). A power-law interpretation of the resulting Taylor-coefficients may not be accurate." << LogIO::POST;
1171 :
1172 : }
1173 : }
1174 :
1175 :
1176 0 : return true;
1177 : }
1178 :
1179 : // Copied from MFCleanImageSkyModel
1180 0 : void WBCleanImageSkyModel::blankOverlappingModels(){
1181 0 : if(nfields_p == 1) return;
1182 :
1183 0 : for(Int taylor=0;taylor<ntaylor_p;taylor++)
1184 : {
1185 0 : for (Int field=0;field<nfields_p-1; ++field)
1186 : {
1187 0 : Int model=getModelIndex(field,taylor);
1188 0 : CoordinateSystem cs0=image(model).coordinates();
1189 0 : IPosition iblc0(image(model).shape().nelements(),0);
1190 :
1191 0 : IPosition itrc0(image(model).shape());
1192 0 : itrc0=itrc0-Int(1);
1193 0 : LCBox lbox0(iblc0, itrc0, image(model).shape());
1194 :
1195 0 : ImageRegion imagreg0(WCBox(lbox0, cs0));
1196 0 : for (Int nextfield=field+1; nextfield < nfields_p; ++nextfield)
1197 : {
1198 0 : Int nextmodel = getModelIndex(nextfield, taylor);
1199 0 : CoordinateSystem cs=image(nextmodel).coordinates();
1200 0 : IPosition iblc(image(nextmodel).shape().nelements(),0);
1201 :
1202 0 : IPosition itrc(image(nextmodel).shape());
1203 0 : itrc=itrc-Int(1);
1204 :
1205 0 : LCBox lbox(iblc, itrc, image(nextmodel).shape());
1206 :
1207 0 : ImageRegion imagreg(WCBox(lbox, cs));
1208 : try{
1209 0 : LatticeRegion latReg=imagreg.toLatticeRegion(image(model).coordinates(), image(model).shape());
1210 0 : ArrayLattice<Bool> pixmask(latReg.get());
1211 0 : SubImage<Float> partToMask(image(model), imagreg, true);
1212 0 : LatticeExpr<Float> myexpr(iif(pixmask, 0.0, partToMask) );
1213 0 : partToMask.copyData(myexpr);
1214 :
1215 : }
1216 0 : catch(...){
1217 : //no overlap you think ?
1218 : //cout << "Did i fail " << endl;
1219 0 : continue;
1220 : }
1221 :
1222 :
1223 : }
1224 :
1225 :
1226 :
1227 : }// for field
1228 : }// for taylor
1229 : }
1230 :
1231 : // Copied from MFCleanImageSkyModel
1232 0 : void WBCleanImageSkyModel::restoreOverlappingModels(){
1233 0 : LogIO os(LogOrigin("WBImageSkyModel","restoreOverlappingModels"));
1234 0 : if(nfields_p == 1) return;
1235 :
1236 0 : for(Int taylor=0;taylor<ntaylor_p;taylor++)
1237 : {
1238 :
1239 0 : for (Int field=0;field<nfields_p-1; ++field)
1240 : {
1241 0 : Int model = getModelIndex(field,taylor);
1242 0 : CoordinateSystem cs0=image(model).coordinates();
1243 0 : IPosition iblc0(image(model).shape().nelements(),0);
1244 0 : IPosition itrc0(image(model).shape());
1245 0 : itrc0=itrc0-Int(1);
1246 0 : LCBox lbox0(iblc0, itrc0, image(model).shape());
1247 0 : ImageRegion imagreg0(WCBox(lbox0, cs0));
1248 :
1249 0 : for (Int nextfield=field+1; nextfield < nfields_p; ++nextfield)
1250 : {
1251 0 : Int nextmodel = getModelIndex(nextfield,taylor);
1252 0 : CoordinateSystem cs=image(nextmodel).coordinates();
1253 0 : IPosition iblc(image(nextmodel).shape().nelements(),0);
1254 :
1255 0 : IPosition itrc(image(nextmodel).shape());
1256 0 : itrc=itrc-Int(1);
1257 :
1258 0 : LCBox lbox(iblc, itrc, image(nextmodel).shape());
1259 :
1260 0 : ImageRegion imagreg(WCBox(lbox, cs));
1261 : try{
1262 0 : LatticeRegion latReg0=imagreg0.toLatticeRegion(image(nextmodel).coordinates(), image(nextmodel).shape());
1263 0 : LatticeRegion latReg=imagreg.toLatticeRegion(image(model).coordinates(), image(model).shape());
1264 0 : ArrayLattice<Bool> pixmask(latReg.get());
1265 :
1266 0 : SubImage<Float> partToMerge(image(nextmodel), imagreg0, true);
1267 0 : SubImage<Float> partToUnmask(image(model), imagreg, true);
1268 :
1269 0 : LatticeExpr<Float> myexpr0(iif(pixmask,partToMerge,partToUnmask));
1270 0 : partToUnmask.copyData(myexpr0);
1271 :
1272 : }
1273 0 : catch(AipsError x){
1274 : /*
1275 : os << LogIO::WARN
1276 : << "no overlap or failure of copying the clean components"
1277 : << x.getMesg()
1278 : << LogIO::POST;
1279 : */
1280 0 : continue;
1281 : }
1282 : }// for field - inner
1283 : }// for field - outer
1284 : }// for taylor
1285 : }
1286 :
1287 0 : Bool WBCleanImageSkyModel::mergeDataError(ImageInterface<Float> &data, ImageInterface<Float> &error, const String &outImg)
1288 : ///Bool WBCleanImageSkyModel::mergeDataError(const String &dataImg, const String &errorImg, const String &outImg)
1289 : {
1290 0 : LogIO os(LogOrigin("WBImageSkyModel",__FUNCTION__));
1291 :
1292 : // open the data and the error image
1293 : // ImageInterface<Float> *data = new PagedImage<Float>(dataImg, TableLock::AutoNoReadLocking);
1294 : // ImageInterface<Float> *error = new PagedImage<Float>(errorImg, TableLock::AutoNoReadLocking);
1295 :
1296 : // create the tiled shape for the output image
1297 0 : IPosition newShape=IPosition(data.shape());
1298 0 : newShape.append(IPosition(1, 2));
1299 0 : TiledShape tiledShape(newShape);
1300 :
1301 : // create the coordinate system for the output image
1302 0 : CoordinateSystem newCSys = data.coordinates();
1303 0 : Vector<Int> quality(2);
1304 0 : quality(0) = Quality::DATA;
1305 0 : quality(1) = Quality::ERROR;
1306 0 : QualityCoordinate qualAxis(quality);
1307 0 : newCSys.addCoordinate(qualAxis);
1308 :
1309 0 : Array<Float> outData=Array<Float>(newShape, 0.0f);
1310 0 : Array<Bool> outMask;
1311 :
1312 : // get all the data values
1313 0 : Array<Float> inData;
1314 0 : Slicer inSlicer(IPosition((data.shape()).size(), 0), IPosition(data.shape()));
1315 0 : data.doGetSlice(inData, inSlicer);
1316 :
1317 : // define in the output array
1318 : // the slicers for data and error
1319 : Int qualCooPos, qualIndex;
1320 0 : qualCooPos = newCSys.findCoordinate(Coordinate::QUALITY);
1321 0 : (newCSys.qualityCoordinate(qualCooPos)).toPixel(qualIndex, Quality::DATA);
1322 0 : IPosition outStart(newShape.size(), 0);
1323 0 : outStart(newShape.size()-1)=qualIndex;
1324 0 : IPosition outLength(newShape);
1325 0 : outLength(newShape.size()-1)=1;
1326 0 : Slicer outDataSlice(outStart, outLength);
1327 0 : (newCSys.qualityCoordinate(qualCooPos)).toPixel(qualIndex, Quality::ERROR);
1328 0 : outStart(newShape.size()-1)=qualIndex;
1329 0 : Slicer outErrorSlice(outStart, outLength);
1330 :
1331 : // add the data values to the output array
1332 0 : outData(outDataSlice) = inData.addDegenerate(1);
1333 :
1334 : // get all the error values
1335 0 : error.doGetSlice(inData, inSlicer);
1336 :
1337 :
1338 : // add the error values to the output array
1339 0 : outData(outErrorSlice) = inData.addDegenerate(1);
1340 :
1341 : // check whether a mask is necessary
1342 0 : if (data.hasPixelMask() || error.hasPixelMask()){
1343 0 : Array<Bool> inMask;
1344 :
1345 0 : outMask=Array<Bool>(newShape, true);
1346 :
1347 : // make the mask for the data values
1348 0 : if (data.hasPixelMask()){
1349 0 : inMask = (data.pixelMask()).get();
1350 : }
1351 : else{
1352 0 : inMask = Array<Bool>(data.shape(), true);
1353 : }
1354 :
1355 : // add the data mask to the output
1356 0 : outMask(outDataSlice) = inMask.addDegenerate(1);
1357 :
1358 : // make the mask for the error values
1359 0 : if (error.hasPixelMask()){
1360 0 : inMask = (error.pixelMask()).get();
1361 : }
1362 : else{
1363 0 : inMask = Array<Bool>(error.shape(), true);
1364 : }
1365 :
1366 : // add the data mask to the output
1367 0 : outMask(outErrorSlice) = inMask.addDegenerate(1);
1368 : }
1369 :
1370 :
1371 : // write out the combined image
1372 0 : ImageUtilities::writeImage(tiledShape, newCSys, outImg, outData, os, outMask);
1373 :
1374 : // delete data;
1375 : // delete error;
1376 :
1377 0 : return true;
1378 : }
1379 :
1380 : } //# NAMESPACE CASA - END
1381 :
|