Coverage for /home/casatest/venv/lib/python3.12/site-packages/casatasks/private/task_tclean.py: 47%
272 statements
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-21 07:43 +0000
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-21 07:43 +0000
1################################################
2# Refactored Clean task
3#
4# v1.0: 2012.10.05, U.R.V.
5#
6################################################
8import platform
9import os
10import shutil
11import numpy
12import copy
13import filecmp
14import time
15import pdb
18from casatasks import casalog
20from casatasks.private.imagerhelpers.imager_base import PySynthesisImager
21from casatasks.private.imagerhelpers.input_parameters import saveparams2last
22from casatasks.private.imagerhelpers.imager_parallel_continuum import PyParallelContSynthesisImager
23from casatasks.private.imagerhelpers.imager_parallel_cube import PyParallelCubeSynthesisImager
24from casatasks.private.imagerhelpers.imager_mtmfs_via_cube import PyMtmfsViaCubeSynthesisImager
25from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
26from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
27from .cleanhelper import write_tclean_history, get_func_params
28from casatools import table
29from casatools import image
30from casatools import synthesisutils
31from casatools import synthesisimager
33try:
34 from casampi.MPIEnvironment import MPIEnvironment
35 from casampi import MPIInterface
37 mpi_available = True
38except ImportError:
39 mpi_available = False
42# if you want to save tclean.last.* from python call of tclean uncomment the decorator
43#@saveparams2last(multibackup=True)
44def tclean(
45 ####### Data Selection
46 vis, # ='',
47 selectdata,
48 field, # ='',
49 spw, # ='',
50 timerange, # ='',
51 uvrange, # ='',
52 antenna, # ='',
53 scan, # ='',
54 observation, # ='',
55 intent, # ='',
56 datacolumn, # ='corrected',
57 ####### Image definition
58 imagename, # ='',
59 imsize, # =[100,100],
60 cell, # =['1.0arcsec','1.0arcsec'],
61 phasecenter, # ='J2000 19:59:28.500 +40.44.01.50',
62 stokes, # ='I',
63 projection, # ='SIN',
64 startmodel, # ='',
65 ## Spectral parameters
66 specmode, # ='mfs',
67 reffreq, # ='',
68 nchan, # =1,
69 start, # ='',
70 width, # ='',
71 outframe, # ='LSRK',
72 veltype, # ='',
73 restfreq, # =[''],
74 # sysvel,#='',
75 # sysvelframe,#='',
76 interpolation, # ='',
77 perchanweightdensity, # =''
78 ##
79 ####### Gridding parameters
80 gridder, # ='ft',
81 facets, # =1,
82 psfphasecenter, # ='',
83 wprojplanes, # =1,
84 ### PB
85 vptable,
86 mosweight, # =True
87 aterm, # =True,
88 psterm, # =True,
89 wbawp, # = True,
90 conjbeams, # = True,
91 cfcache, # = "",
92 usepointing, # =false
93 computepastep, # =360.0,
94 rotatepastep, # =360.0,
95 pointingoffsetsigdev, # =[10.0],
96 pblimit, # =0.01,
97 normtype, # ='flatnoise',
98 ####### Deconvolution parameters
99 deconvolver, # ='hogbom',
100 scales, # =[],
101 nterms, # =1,
102 smallscalebias, # =0.0
103 fusedthreshold, # =0.0
104 largestscale, # =-1
105 ### restoration options
106 restoration,
107 restoringbeam, # =[],
108 pbcor,
109 ##### Outliers
110 outlierfile, # ='',
111 ##### Weighting
112 weighting, # ='natural',
113 robust, # =0.5,
114 noise, # 0.0Jy
115 npixels, # =0,
116 # uvtaper,#=False,
117 uvtaper, # =[],
118 ##### Iteration control
119 niter,#=0,
120 gain,#=0.1,
121 threshold,#=0.0,
122 nsigma,#=0.0
123 cycleniter,#=0,
124 cyclefactor,#=1.0,
125 minpsffraction,#=0.1,
126 maxpsffraction,#=0.8,
127 interactive,#=False,
128 nmajor,#=-1,
129 fullsummary,#=False,
131 ##### (new) Mask parameters
132 usemask, # ='user',
133 mask, # ='',
134 pbmask, # ='',
135 # maskthreshold,#='',
136 # maskresolution,#='',
137 # nmask,#=0,
138 ##### automask by multithresh
139 sidelobethreshold, # =5.0,
140 noisethreshold, # =3.0,
141 lownoisethreshold, # =3.0,
142 negativethreshold, # =0.0,
143 smoothfactor, # =1.0,
144 minbeamfrac, # =0.3,
145 cutthreshold, # =0.01,
146 growiterations, # =100
147 dogrowprune, # =True
148 minpercentchange, # =0.0
149 verbose, # =False
150 fastnoise, # =False
151 ## Misc
152 restart, # =True,
153 savemodel, # ="none",
154 # makeimages,#="auto"
155 calcres, # =True,
156 calcpsf, # =True,
157 psfcutoff, # =0.35
158 ####### State parameters
159 parallel,
160): # =False):
162 #####################################################
163 #### Sanity checks and controls
164 #####################################################
165 ### Move these checks elsewhere ?
166 inpparams=locals().copy()
167# saveinputs(inpparams)
168 ###now deal with parameters which are not the same name
169 inpparams['msname']= inpparams.pop('vis')
170 inpparams['timestr']= inpparams.pop('timerange')
171 inpparams['uvdist']= inpparams.pop('uvrange')
172 inpparams['obs']= inpparams.pop('observation')
173 inpparams['state']= inpparams.pop('intent')
174 inpparams['loopgain']=inpparams.pop('gain')
175 inpparams['scalebias']=inpparams.pop('smallscalebias')
176 #
177 # Force chanchunks=1 always now (CAS-13400)
178 inpparams['chanchunks']=1
180 if specmode=='cont':
181 specmode='mfs'
182 inpparams['specmode']='mfs'
183# if specmode=='mfs' and nterms==1 and deconvolver == "mtmfs":
184# casalog.post( "The MTMFS deconvolution algorithm (deconvolver='mtmfs') needs nterms>1.Please set nterms=2 (or more). ", "WARN", "task_tclean" )
185# return
187 # Force chanchunks=1 always now (CAS-13400)
188 inpparams["chanchunks"] = 1
190 if specmode == "cont":
191 specmode = "mfs"
192 inpparams["specmode"] = "mfs"
193 # if specmode=='mfs' and nterms==1 and deconvolver == "mtmfs":
194 # casalog.post( "The MTMFS deconvolution algorithm (deconvolver='mtmfs') needs nterms>1.Please set nterms=2 (or more). ", "WARN", "task_tclean" )
195 # return
197 if deconvolver == "mtmfs" and (specmode == "cube" or specmode == "cubedata"):
198 casalog.post(
199 "The MSMFS algorithm (deconvolver='mtmfs') with specmode='cube' is not supported",
200 "WARN",
201 "task_tclean",
202 )
203 return
205 if (
206 (specmode == "cube" or specmode == "cubedata" or specmode == "cubesource")
207 ) and (parallel == False and mpi_available and MPIEnvironment.is_mpi_enabled):
208 casalog.post(
209 "When CASA is launched with mpi, the parallel=False option has no effect for 'cube' imaging for gridder='mosaic','wproject','standard' and major cycles are always executed in parallel.\n",
210 "WARN",
211 "task_tclean",
212 )
213 # casalog.post( "Setting parameter parallel=False with specmode='cube' when launching CASA with mpi has no effect except for awproject.", "WARN", "task_tclean" )
215 ## Part of CAS-13814, checking for the only options compatible with mtmfs_via_cube.
216 if specmode=="mvc":
217 if deconvolver != 'mtmfs' or nterms<=1 :
218 casalog.post("The specmode='mvc' option requires the deconvolver to be 'mtmfs' and 'nterms>1.",
219 "WARN",
220 "task_tclean")
221 return
223 ## Part of CAS-13814, moving warnings about pbcor and widebandpbcor from the C++ code to here, for better access to user-settings.
224 if specmode=='mfs' and deconvolver=='mtmfs' and gridder in ['standard','mosaic'] and pbcor==True:
225 casalog.post("For specmode='mfs' and deconvolver='mtmfs', the option of pbcor=True divides each restored Taylor coefficient image by the pb.tt0 image. This correction ignores the frequency-dependence of the primary beam and does not correct for PB spectral index. It is scientifically valid only for small fractional bandwidths. For more accurate wideband primary beam correction (if needed), please use one of the following options : (1) specmode='mvc' with gridder='standard' or 'mosaic' with pbcor=True, (2) conjbeams=True and wbawp=True with gridder='awproject' and pbcor=True.",
226 "WARN",
227 "task_tclean")
228 if perchanweightdensity == False and weighting == "briggsbwtaper":
229 casalog.post(
230 "The briggsbwtaper weighting scheme is not compatable with perchanweightdensity=False.",
231 "WARN",
232 "task_tclean",
233 )
235 if (specmode == "mfs" or specmode == "cont") and weighting == "briggsbwtaper":
236 casalog.post(
237 "The briggsbwtaper weighting scheme is not compatable with specmode='mfs' or 'cont'.",
238 "WARN",
239 "task_tclean",
240 )
241 return
243 if npixels != 0 and weighting == "briggsbwtaper":
244 casalog.post(
245 "The briggsbwtaper weighting scheme is not compatable with npixels != 0.",
246 "WARN",
247 "task_tclean",
248 )
249 return
251 if facets > 1 and parallel == True:
252 casalog.post(
253 "Facetted imaging currently works only in serial. Please choose pure W-projection instead.",
254 "WARN",
255 "task_tclean",
256 )
258 if nmajor < -1:
259 casalog.post(
260 "Negative values less than -1 for nmajor are reserved for possible future implementation",
261 "WARN",
262 "task_tclean",
263 )
264 return
266 ## CAS-13814
267 if (specmode == "mvc" and gridder == 'awproject' and (conjbeams==True or wbawp==False) ):
268 casalog.post(
269 "specmode='mvc' requires frequency-dependent primary beams to be used during cube gridding. Please set conjbeams=False and wbawp=True for the awproject gridder.",
270 "WARN",
271 "task_tclean",
272 )
273 return
275 #CAS-13814
276 if (specmode == "mvc" and gridder == 'mosaic' and conjbeams==True):
277 casalog.post(
278 "specmode='mvc' requires frequency-dependent primary beams to be used during cube gridding. Please set conjbeams=False with the mosaic gridder.",
279 "WARN",
280 "task_tclean",
281 )
282 return
284 # CAS-14146
285 if (specmode == "mfs" and deconvolver == 'mtmfs' and (gridder == 'mosaic' or gridder == 'awp2')):
286 casalog.post(
287 "Please consider using specmode=mvc with " + gridder + " gridder"
288 " as this gridder does not implement conjbeams \n thus it needs a few major cycles to converge towards the correct answer",
289 "WARN",
290 "task_tclean",
291 )
293 # CAS-13581
294 # XXX : Remove this once awp-hpg is released for general use
295 if gridder == 'awphpg':
296 casalog.post(
297 "The awphpg gridder is not available for general use in the CASA 6.7.0 release. It will be made available in a future release.",
298 "WARN",
299 "task_tclean",
300 )
302 #####################################################
303 #### Construct ImagerParameters object
304 #####################################################
306 imager = None
307 paramList = None
309 # Put all parameters into dictionaries and check them.
310 ##make a dictionary of parameters that ImagerParameters take
312 defparm = dict(
313 list(
314 zip(
315 ImagerParameters.__init__.__code__.co_varnames[1:],
316 ImagerParameters.__init__.__defaults__,
317 )
318 )
319 )
320 ###assign values to the ones passed to tclean and if not defined yet in tclean...
321 ###assign them the default value of the constructor
322 bparm = {k: inpparams[k] if k in inpparams else defparm[k] for k in defparm.keys()}
324 ###default mosweight=True is tripping other gridders as they are not
325 ###expecting it to be true
326 if bparm["mosweight"] == True and (not bparm["gridder"] in ['mosaic', 'awp2']):
327 bparm["mosweight"] = False
329 if specmode == "mfs":
330 bparm["perchanweightdensity"] = False
332 # deprecation message
333 if usemask == "auto-thresh" or usemask == "auto-thresh2":
334 casalog.post(
335 usemask
336 + " is deprecated, will be removed in CASA 5.4. It is recommended to use auto-multithresh instead",
337 "WARN",
338 )
341 #paramList.printParameters()
344 if len(pointingoffsetsigdev)>0 and pointingoffsetsigdev[0]!=0.0 and usepointing==True and gridder.count('awproj')>1:
345 casalog.post("pointingoffsetsigdev will be used for pointing corrections with AWProjection", "WARN")
346# elif usepointing==True and pointingoffsetsigdev[0] == 0:
347# casalog.post("pointingoffsetsigdev is set to zero which is an unphysical value, will proceed with the native sky pixel resolution instead". "WARN")
349 if (
350 len(pointingoffsetsigdev) > 0
351 and pointingoffsetsigdev[0] != 0.0
352 and usepointing == True
353 and gridder.count("awproj") > 1
354 ):
355 casalog.post(
356 "pointingoffsetsigdev will be used for pointing corrections with AWProjection",
357 "WARN",
358 )
359 # elif usepointing==True and pointingoffsetsigdev[0] == 0:
360 # casalog.post("pointingoffsetsigdev is set to zero which is an unphysical value, will proceed with the native sky pixel resolution instead". "WARN")
362 ##pcube may still need to be set to True for some combination of ftmachine etc...
363 # =========================================================
364 concattype = ""
365 pcube = False
366 if parallel == True and specmode != "mfs":
367 if specmode != "mfs":
368 pcube = False
369 parallel = False
370 else:
371 pcube = True
372 # =========================================================
373 ####set the children to load c++ libraries and applicator
374 ### make workers ready for c++ based mpicommands
375 cppparallel = False
376 if (
377 mpi_available
378 and MPIEnvironment.is_mpi_enabled
379 and specmode != "mfs"
380 and not pcube
381 ):
382 mint = MPIInterface.MPIInterface()
383 cl = mint.getCluster()
384 cl._cluster.pgc("from casatools import synthesisimager", False)
385 cl._cluster.pgc("si=synthesisimager()", False)
386 cl._cluster.pgc("si.initmpi()", False)
387 cppparallel = True
388 ###ignore chanchunk
389 bparm['chanchunks']=1
390 ######awphpg case
391 if(gridder=='awphpg'):
392 localsi=synthesisimager()
393 localsi.inithpg()
394 # catch non operational case (parallel cube tclean with interative=T)
395 if pcube and interactive:
396 casalog.post(
397 "Interactive mode is not currently supported with parallel apwproject cube CLEANing, please restart by setting interactive=F",
398 "WARN",
399 "task_tclean",
400 )
401 return False
404 if interactive:
405 # catch non operational case (parallel cube tclean with interative=T)
406 if pcube:
407 casalog.post(
408 "Interactive mode is not currently supported with parallel apwproject cube CLEANing, please restart by setting interactive=F",
409 "WARN",
410 "task_tclean",
411 )
412 return False
414 # Check for casaviewer, if it does not exist flag it up front for macOS
415 # since casaviewer is no longer provided by default with macOS. Returning
416 # False instead of throwing an exception results in:
417 #
418 # RuntimeError: No active exception to reraise
419 #
420 # from tclean run from casashell.
421 try:
422 import casaviewer as __test_casaviewer
423 except:
424 if platform.system( ) == "Darwin":
425 casalog.post(
426 "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol Please restart by setting interactive=F",
427 "WARN",
428 "task_tclean",
429 )
430 raise RuntimeError( "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol" )
433 #casalog.post('parameters {}'.format(bparm))
434 paramList=ImagerParameters(**bparm)
436 ## Setup Imager objects, for different parallelization schemes.
437 imagerInst = PySynthesisImager
438 if specmode == "mvc":
439 imager = PyMtmfsViaCubeSynthesisImager(params=paramList)
440 imagerInst = PyMtmfsViaCubeSynthesisImager
441 elif parallel == False and pcube == False:
442 imager = PySynthesisImager(params=paramList)
443 imagerInst = PySynthesisImager
444 elif parallel == True:
445 imager = PyParallelContSynthesisImager(params=paramList)
446 imagerInst = PySynthesisImager
447 elif pcube == True:
448 imager = PyParallelCubeSynthesisImager(params=paramList)
449 imagerInst = PyParallelCubeSynthesisImager
450 # virtualconcat type - changed from virtualmove to virtualcopy 2016-07-20
451 # using ia.imageconcat now the name changed to copyvirtual 2019-08-12
452 concattype = "copyvirtual"
453 else:
454 casalog.post("Invalid parallel combination in doClean.", "ERROR")
455 return
457 retrec = {}
459 try:
460 # if (1):
461 # pdb.set_trace()
462 ## Init major cycle elements
463 t0 = time.time()
464 imager.initializeImagers()
466 # Construct the CFCache for AWProject-class of FTMs. For
467 # other choices the following three calls become NoOps.
468 # imager.dryGridding();
469 # imager.fillCFCache();
470 # imager.reloadCFCache();
472 imager.initializeNormalizers()
473 imager.setWeighting()
474 t1 = time.time()
475 casalog.post(
476 "***Time for initializing imager and normalizers: "
477 + "%.2f" % (t1 - t0)
478 + " sec",
479 "INFO3",
480 "task_tclean",
481 )
483 ## Init minor cycle elements
484 if niter > 0 or restoration == True:
485 t0 = time.time()
486 imager.initializeDeconvolvers()
487 t1 = time.time()
488 casalog.post(
489 "***Time for initializing deconvolver(s): "
490 + "%.2f" % (t1 - t0)
491 + " sec",
492 "INFO3",
493 "task_tclean",
494 )
496 ####now is the time to check estimated memory
497 imager.estimatememory()
499 if niter > 0:
500 t0 = time.time()
501 imager.initializeIterationControl()
502 t1 = time.time()
503 casalog.post(
504 "***Time for initializing iteration controller: "
505 + "%.2f" % (t1 - t0)
506 + " sec",
507 "INFO3",
508 "task_tclean",
509 )
511 ## Make PSF
513 if calcpsf==True:
514 t0=time.time();
515 #####TESTOO
516 if(gridder=="awphpg" and specmode=="mfs"):
517 imager.makePB()
518 #####TESTOO
519 imager.makePSF()
520 if (psfphasecenter != "") and ("mosaic" in gridder):
521 ###for some reason imager keeps the psf open delete it and recreate it afterwards
522 imager.deleteTools()
523 mytb = table()
524 psfname = (
525 bparm["imagename"] + ".psf.tt0"
526 if (os.path.exists(bparm["imagename"] + ".psf.tt0"))
527 else bparm["imagename"] + ".psf"
528 )
529 mytb.open(psfname)
530 miscinf = mytb.getkeyword("miscinfo")
531 iminf = mytb.getkeyword("imageinfo")
532 # casalog.post ('miscinfo {} {}'.format(miscinf, iminf))
533 mytb.done()
534 casalog.post("doing with different phasecenter psf")
535 imager.unlockimages(0)
536 psfParameters = paramList.getAllPars()
537 psfParameters["phasecenter"] = psfphasecenter
538 psfParamList = ImagerParameters(**psfParameters)
539 psfimager = imagerInst(params=psfParamList)
540 psfimager.initializeImagers()
541 psfimager.setWeighting()
542 psfimager.makeImage("psf", psfParameters["imagename"] + ".psf")
543 psfimager.deleteTools()
544 mytb.open(psfname, nomodify=False)
545 mytb.putkeyword("imageinfo", iminf)
546 mytb.putkeyword("miscinfo", miscinf)
547 mytb.done()
548 mysu=synthesisutils()
549 mysu.fitPsfBeam(imagename=bparm['imagename'],
550 nterms=(bparm['nterms'] if deconvolver=="mtmfs" else 1),
551 psfcutoff=bparm['psfcutoff'])
552 imager = PySynthesisImager(params=paramList)
553 imager.initializeImagers()
554 imager.initializeNormalizers()
555 imager.setWeighting()
556 ###redo these as we destroyed things for lock issues
557 ## Init minor cycle elements
558 if niter > 0 or restoration == True:
559 imager.initializeDeconvolvers()
560 if niter > 0:
561 imager.initializeIterationControl()
563 t1 = time.time()
564 if specmode != "mfs" and ("stand" in gridder):
565 casalog.post(
566 "***Time for making PSF and PB: " + "%.2f" % (t1 - t0) + " sec",
567 "INFO3",
568 "task_tclean",
569 )
570 else:
571 casalog.post(
572 "***Time for making PSF: " + "%.2f" % (t1 - t0) + " sec",
573 "INFO3",
574 "task_tclean",
575 )
577 imager.makePB()
579 t2 = time.time()
580 if specmode == "mfs" and ("stand" in gridder):
581 casalog.post(
582 "***Time for making PB: " + "%.2f" % (t2 - t1) + " sec",
583 "INFO3",
584 "task_tclean",
585 )
587 if gridder in ["mosaic", "awproject"]:
588 imager.checkPB()
590 if niter >= 0:
592 ## Make dirty image
593 if calcres == True:
594 t0 = time.time()
595 imager.runMajorCycle(isCleanCycle=False)
596 t1 = time.time()
597 casalog.post(
598 "***Time for major cycle (calcres=T): "
599 + "%.2f" % (t1 - t0)
600 + " sec",
601 "INFO3",
602 "task_tclean",
603 )
605 ## In case of no deconvolution iterations....
606 if niter == 0 and calcres == False:
607 if savemodel != "none":
608 imager.predictModel()
610 # CAS-13960 : Construct return dict for niter=0 case
611 # If residual image does not exist, summaryminor will not be
612 # populated.
613 if niter==0:
614 id = ImagingDict()
615 retrec = id.construct_residual_dict(paramList)
617 ## Do deconvolution and iterations
618 if niter > 0:
619 t0 = time.time()
622 isit = imager.hasConverged()
623 imager.updateMask()
624 # if((type(usemask)==str) and ('auto' in usemask)):
625 # isit = imager.hasConverged()
626 isit = imager.hasConverged()
627 t1 = time.time()
628 casalog.post(
629 "***Time to update mask: " + "%.2f" % (t1 - t0) + " sec",
630 "INFO3",
631 "task_tclean",
632 )
633 while not isit:
634 t0 = time.time()
635 ### sometimes after automasking it does not do anything
636 doneMinor = imager.runMinorCycle()
637 t1 = time.time()
638 casalog.post(
639 "***Time for minor cycle: " + "%.2f" % (t1 - t0) + " sec",
640 "INFO3",
641 "task_tclean",
642 )
644 t0 = time.time()
645 if doneMinor:
646 imager.runMajorCycle()
647 t1 = time.time()
648 casalog.post(
649 "***Time for major cycle: " + "%.2f" % (t1 - t0) + " sec",
650 "INFO3",
651 "task_tclean",
652 )
654 imager.updateMask()
655 t2 = time.time()
656 casalog.post(
657 "***Time to update mask: " + "%.2f" % (t2 - t1) + " sec",
658 "INFO3",
659 "task_tclean",
660 )
661 isit = imager.hasConverged() or (not doneMinor)
663 ## Get summary from iterbot
664 #if type(interactive) != bool:
665 retrec=imager.getSummary(fullsummary);
667 if savemodel!='none' and (interactive==True or usemask=='auto-multithresh' or nsigma>0.0):
668 paramList.resetParameters()
669 if parallel and specmode == "mfs":
670 # For parallel mfs, also needs to reset the parameters for each node
671 imager.resetSaveModelParams(paramList)
672 imager.initializeImagers()
673 imager.predictModel()
675 ## Restore images.
676 if restoration == True:
677 t0 = time.time()
678 imager.restoreImages()
679 t1 = time.time()
680 casalog.post(
681 "***Time for restoring images: " + "%.2f" % (t1 - t0) + " sec",
682 "INFO3",
683 "task_tclean",
684 )
685 if pbcor == True:
686 t0 = time.time()
687 imager.pbcorImages()
688 t1 = time.time()
689 casalog.post(
690 "***Time for pb-correcting images: "
691 + "%.2f" % (t1 - t0)
692 + " sec",
693 "INFO3",
694 "task_tclean",
695 )
696 ######### niter >=0 end if
698 finally:
699 ##close tools
700 # needs to deletools before concat or lock waits for ever
701 if imager != None:
702 imager.deleteTools()
703 if cppparallel:
704 ###release workers back to python mpi control
705 si = synthesisimager()
706 si.releasempi()
707 if pcube:
708 casalog.post("running concatImages ...")
709 casalog.post(
710 "Running virtualconcat (type=%s) of sub-cubes" % concattype,
711 "INFO2",
712 "task_tclean",
713 )
714 imager.concatImages(type=concattype)
715 # CAS-10721
716 # if niter>0 and savemodel != "none":
717 # casalog.post("Please check the casa log file for a message confirming that the model was saved after the last major cycle. If it doesn't exist, please re-run tclean with niter=0,calcres=False,calcpsf=False in order to trigger a 'predict model' step that obeys the savemodel parameter.","WARN","task_tclean")
719 # Write history at the end, when hopefully all .workdirectory, .work.temp, etc. are gone
720 # from disk, so they won't be picked up. They need time to disappear on NFS or slow hw.
721 try:
722 params = get_func_params(tclean, locals())
723 write_tclean_history(imagename, "tclean", params, casalog)
724 except Exception as exc:
725 casalog.post("Error updating history (logtable): {} ".format(exc), "WARN")
727 return retrec
730##################################################