Coverage for / home / casatest / venv / lib / python3.12 / site-packages / casatasks / private / task_tclean.py: 56%
264 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 07:14 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 07:14 +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, sanitize_tclean_inputs
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 #####################################################
166 inpparams = locals().copy()
167 # deal with parameters that are not the same name
168 inpparams, defparm = sanitize_tclean_inputs(inpparams)
170 if specmode=='cont':
171 specmode='mfs'
172 inpparams['specmode']='mfs'
173# if specmode=='mfs' and nterms==1 and deconvolver == "mtmfs":
174# casalog.post( "The MTMFS deconvolution algorithm (deconvolver='mtmfs') needs nterms>1.Please set nterms=2 (or more). ", "WARN", "task_tclean" )
175# return
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 if deconvolver == "mtmfs" and (specmode == "cube" or specmode == "cubedata"):
188 casalog.post(
189 "The MSMFS algorithm (deconvolver='mtmfs') with specmode='cube' is not supported",
190 "WARN",
191 "task_tclean",
192 )
193 return
195 if (
196 (specmode == "cube" or specmode == "cubedata" or specmode == "cubesource")
197 ) and (parallel == False and mpi_available and MPIEnvironment.is_mpi_enabled):
198 casalog.post(
199 "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",
200 "WARN",
201 "task_tclean",
202 )
203 # casalog.post( "Setting parameter parallel=False with specmode='cube' when launching CASA with mpi has no effect except for awproject.", "WARN", "task_tclean" )
205 ## Part of CAS-13814, checking for the only options compatible with mtmfs_via_cube.
206 if specmode=="mvc":
207 if deconvolver != 'mtmfs' or nterms<=1 :
208 casalog.post("The specmode='mvc' option requires the deconvolver to be 'mtmfs' and 'nterms>1.",
209 "WARN",
210 "task_tclean")
211 return
213 ## Part of CAS-13814, moving warnings about pbcor and widebandpbcor from the C++ code to here, for better access to user-settings.
214 if specmode=='mfs' and deconvolver=='mtmfs' and gridder in ['standard','mosaic'] and pbcor==True:
215 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.",
216 "WARN",
217 "task_tclean")
218 if perchanweightdensity == False and weighting == "briggsbwtaper":
219 casalog.post(
220 "The briggsbwtaper weighting scheme is not compatable with perchanweightdensity=False.",
221 "WARN",
222 "task_tclean",
223 )
225 if (specmode == "mfs" or specmode == "cont") and weighting == "briggsbwtaper":
226 casalog.post(
227 "The briggsbwtaper weighting scheme is not compatable with specmode='mfs' or 'cont'.",
228 "WARN",
229 "task_tclean",
230 )
231 return
233 if npixels != 0 and weighting == "briggsbwtaper":
234 casalog.post(
235 "The briggsbwtaper weighting scheme is not compatable with npixels != 0.",
236 "WARN",
237 "task_tclean",
238 )
239 return
241 if facets > 1 and parallel == True:
242 casalog.post(
243 "Facetted imaging currently works only in serial. Please choose pure W-projection instead.",
244 "WARN",
245 "task_tclean",
246 )
248 if nmajor < -1:
249 casalog.post(
250 "Negative values less than -1 for nmajor are reserved for possible future implementation",
251 "WARN",
252 "task_tclean",
253 )
254 return
256 ## CAS-13814
257 if (specmode == "mvc" and gridder == 'awproject' and (conjbeams==True or wbawp==False) ):
258 casalog.post(
259 "specmode='mvc' requires frequency-dependent primary beams to be used during cube gridding. Please set conjbeams=False and wbawp=True for the awproject gridder.",
260 "WARN",
261 "task_tclean",
262 )
263 return
265 #CAS-13814
266 if (specmode == "mvc" and gridder == 'mosaic' and conjbeams==True):
267 casalog.post(
268 "specmode='mvc' requires frequency-dependent primary beams to be used during cube gridding. Please set conjbeams=False with the mosaic gridder.",
269 "WARN",
270 "task_tclean",
271 )
272 return
274 # CAS-14146
275 if (specmode == "mfs" and deconvolver == 'mtmfs' and (gridder == 'mosaic' or gridder == 'awp2')):
276 casalog.post(
277 "Please consider using specmode=mvc with " + gridder + " gridder"
278 " as this gridder does not implement conjbeams \n thus it needs a few major cycles to converge towards the correct answer",
279 "WARN",
280 "task_tclean",
281 )
283 # CAS-13581
284 # XXX : Remove this once awp-hpg is released for general use
285 if gridder == 'awphpg':
286 casalog.post(
287 "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.",
288 "WARN",
289 "task_tclean",
290 )
292 #####################################################
293 #### Construct ImagerParameters object
294 #####################################################
296 imager = None
297 paramList = None
299 ###assign values to the ones passed to tclean and if not defined yet in tclean...
300 ###assign them the default value of the constructor
301 bparm = {k: inpparams[k] if k in inpparams else defparm[k] for k in defparm.keys()}
303 ###default mosweight=True is tripping other gridders as they are not
304 ###expecting it to be true
305 if bparm["mosweight"] == True and (not bparm["gridder"] in ['mosaic', 'awp2']):
306 bparm["mosweight"] = False
308 if specmode == "mfs":
309 bparm["perchanweightdensity"] = False
311 # deprecation message
312 if usemask == "auto-thresh" or usemask == "auto-thresh2":
313 casalog.post(
314 usemask
315 + " is deprecated, will be removed in CASA 5.4. It is recommended to use auto-multithresh instead",
316 "WARN",
317 )
320 #paramList.printParameters()
323 if len(pointingoffsetsigdev)>0 and pointingoffsetsigdev[0]!=0.0 and usepointing==True and gridder.count('awproj')>1:
324 casalog.post("pointingoffsetsigdev will be used for pointing corrections with AWProjection", "WARN")
325# elif usepointing==True and pointingoffsetsigdev[0] == 0:
326# casalog.post("pointingoffsetsigdev is set to zero which is an unphysical value, will proceed with the native sky pixel resolution instead". "WARN")
328 if (
329 len(pointingoffsetsigdev) > 0
330 and pointingoffsetsigdev[0] != 0.0
331 and usepointing == True
332 and gridder.count("awproj") > 1
333 ):
334 casalog.post(
335 "pointingoffsetsigdev will be used for pointing corrections with AWProjection",
336 "WARN",
337 )
338 # elif usepointing==True and pointingoffsetsigdev[0] == 0:
339 # casalog.post("pointingoffsetsigdev is set to zero which is an unphysical value, will proceed with the native sky pixel resolution instead". "WARN")
341 ##pcube may still need to be set to True for some combination of ftmachine etc...
342 # =========================================================
343 concattype = ""
344 pcube = False
345 if parallel == True and specmode != "mfs":
346 if specmode != "mfs":
347 pcube = False
348 parallel = False
349 else:
350 pcube = True
351 # =========================================================
352 ####set the children to load c++ libraries and applicator
353 ### make workers ready for c++ based mpicommands
354 cppparallel = False
355 if (
356 mpi_available
357 and MPIEnvironment.is_mpi_enabled
358 and specmode != "mfs"
359 and not pcube
360 ):
361 mint = MPIInterface.MPIInterface()
362 cl = mint.getCluster()
363 cl._cluster.pgc("from casatools import synthesisimager", False)
364 cl._cluster.pgc("si=synthesisimager()", False)
365 cl._cluster.pgc("si.initmpi()", False)
366 cppparallel = True
367 ###ignore chanchunk
368 bparm['chanchunks']=1
369 ######awphpg case
370 if(gridder=='awphpg'):
371 localsi=synthesisimager()
372 localsi.inithpg()
373 # catch non operational case (parallel cube tclean with interative=T)
374 if pcube and interactive:
375 casalog.post(
376 "Interactive mode is not currently supported with parallel apwproject cube CLEANing, please restart by setting interactive=F",
377 "WARN",
378 "task_tclean",
379 )
380 return False
383 if interactive:
384 # catch non operational case (parallel cube tclean with interative=T)
385 if pcube:
386 casalog.post(
387 "Interactive mode is not currently supported with parallel apwproject cube CLEANing, please restart by setting interactive=F",
388 "WARN",
389 "task_tclean",
390 )
391 return False
393 # Check for casaviewer, if it does not exist flag it up front for macOS
394 # since casaviewer is no longer provided by default with macOS. Returning
395 # False instead of throwing an exception results in:
396 #
397 # RuntimeError: No active exception to reraise
398 #
399 # from tclean run from casashell.
400 try:
401 import casaviewer as __test_casaviewer
402 except:
403 if platform.system( ) == "Darwin":
404 casalog.post(
405 "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol Please restart by setting interactive=F",
406 "WARN",
407 "task_tclean",
408 )
409 raise RuntimeError( "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol" )
412 #casalog.post('parameters {}'.format(bparm))
413 paramList=ImagerParameters(**bparm)
415 ## Setup Imager objects, for different parallelization schemes.
416 imagerInst = PySynthesisImager
417 if specmode == "mvc":
418 imager = PyMtmfsViaCubeSynthesisImager(params=paramList)
419 imagerInst = PyMtmfsViaCubeSynthesisImager
420 elif parallel == False and pcube == False:
421 imager = PySynthesisImager(params=paramList)
422 imagerInst = PySynthesisImager
423 elif parallel == True:
424 imager = PyParallelContSynthesisImager(params=paramList)
425 imagerInst = PySynthesisImager
426 elif pcube == True:
427 imager = PyParallelCubeSynthesisImager(params=paramList)
428 imagerInst = PyParallelCubeSynthesisImager
429 # virtualconcat type - changed from virtualmove to virtualcopy 2016-07-20
430 # using ia.imageconcat now the name changed to copyvirtual 2019-08-12
431 concattype = "copyvirtual"
432 else:
433 casalog.post("Invalid parallel combination in doClean.", "ERROR")
434 return
436 retrec = {}
438 try:
439 # if (1):
440 # pdb.set_trace()
441 ## Init major cycle elements
442 t0 = time.time()
443 imager.initializeImagers()
445 # Construct the CFCache for AWProject-class of FTMs. For
446 # other choices the following three calls become NoOps.
447 # imager.dryGridding();
448 # imager.fillCFCache();
449 # imager.reloadCFCache();
451 imager.initializeNormalizers()
452 imager.setWeighting()
453 t1 = time.time()
454 casalog.post(
455 "***Time for initializing imager and normalizers: "
456 + "%.2f" % (t1 - t0)
457 + " sec",
458 "INFO3",
459 "task_tclean",
460 )
462 ## Init minor cycle elements
463 if niter > 0 or restoration == True:
464 t0 = time.time()
465 imager.initializeDeconvolvers()
466 t1 = time.time()
467 casalog.post(
468 "***Time for initializing deconvolver(s): "
469 + "%.2f" % (t1 - t0)
470 + " sec",
471 "INFO3",
472 "task_tclean",
473 )
475 ####now is the time to check estimated memory
476 imager.estimatememory()
478 if niter > 0:
479 t0 = time.time()
480 imager.initializeIterationControl()
481 t1 = time.time()
482 casalog.post(
483 "***Time for initializing iteration controller: "
484 + "%.2f" % (t1 - t0)
485 + " sec",
486 "INFO3",
487 "task_tclean",
488 )
490 ## Make PSF
492 if calcpsf==True:
493 t0=time.time();
494 #####TESTOO
495 if(gridder=="awphpg" and specmode=="mfs"):
496 imager.makePB()
497 #####TESTOO
498 imager.makePSF()
499 if (psfphasecenter != "") and ("mosaic" in gridder):
500 ###for some reason imager keeps the psf open delete it and recreate it afterwards
501 imager.deleteTools()
502 mytb = table()
503 psfname = (
504 bparm["imagename"] + ".psf.tt0"
505 if (os.path.exists(bparm["imagename"] + ".psf.tt0"))
506 else bparm["imagename"] + ".psf"
507 )
508 mytb.open(psfname)
509 miscinf = mytb.getkeyword("miscinfo")
510 iminf = mytb.getkeyword("imageinfo")
511 # casalog.post ('miscinfo {} {}'.format(miscinf, iminf))
512 mytb.done()
513 casalog.post("doing with different phasecenter psf")
514 imager.unlockimages(0)
515 psfParameters = paramList.getAllPars()
516 psfParameters["phasecenter"] = psfphasecenter
517 psfParamList = ImagerParameters(**psfParameters)
518 psfimager = imagerInst(params=psfParamList)
519 psfimager.initializeImagers()
520 psfimager.setWeighting()
521 psfimager.makeImage("psf", psfParameters["imagename"] + ".psf")
522 psfimager.deleteTools()
523 mytb.open(psfname, nomodify=False)
524 mytb.putkeyword("imageinfo", iminf)
525 mytb.putkeyword("miscinfo", miscinf)
526 mytb.done()
527 mysu=synthesisutils()
528 mysu.fitPsfBeam(imagename=bparm['imagename'],
529 nterms=(bparm['nterms'] if deconvolver=="mtmfs" else 1),
530 psfcutoff=bparm['psfcutoff'])
531 imager = PySynthesisImager(params=paramList)
532 imager.initializeImagers()
533 imager.initializeNormalizers()
534 imager.setWeighting()
535 ###redo these as we destroyed things for lock issues
536 ## Init minor cycle elements
537 if niter > 0 or restoration == True:
538 imager.initializeDeconvolvers()
539 if niter > 0:
540 imager.initializeIterationControl()
542 t1 = time.time()
543 if specmode != "mfs" and ("stand" in gridder):
544 casalog.post(
545 "***Time for making PSF and PB: " + "%.2f" % (t1 - t0) + " sec",
546 "INFO3",
547 "task_tclean",
548 )
549 else:
550 casalog.post(
551 "***Time for making PSF: " + "%.2f" % (t1 - t0) + " sec",
552 "INFO3",
553 "task_tclean",
554 )
556 imager.makePB()
558 t2 = time.time()
559 if specmode == "mfs" and ("stand" in gridder):
560 casalog.post(
561 "***Time for making PB: " + "%.2f" % (t2 - t1) + " sec",
562 "INFO3",
563 "task_tclean",
564 )
566 if gridder in ["mosaic", "awproject"]:
567 imager.checkPB()
569 if niter >= 0:
571 ## Make dirty image
572 if calcres == True:
573 t0 = time.time()
574 imager.runMajorCycle(isCleanCycle=False)
575 t1 = time.time()
576 casalog.post(
577 "***Time for major cycle (calcres=T): "
578 + "%.2f" % (t1 - t0)
579 + " sec",
580 "INFO3",
581 "task_tclean",
582 )
584 ## In case of no deconvolution iterations....
585 if niter == 0 and calcres == False:
586 if savemodel != "none":
587 imager.predictModel()
589 # CAS-13960 : Construct return dict for niter=0 case
590 # If residual image does not exist, summaryminor will not be
591 # populated.
592 if niter==0:
593 id = ImagingDict()
594 retrec = id.construct_residual_dict(paramList)
596 ## Do deconvolution and iterations
597 if niter > 0:
598 t0 = time.time()
601 isit = imager.hasConverged()
602 imager.updateMask()
603 # if((type(usemask)==str) and ('auto' in usemask)):
604 # isit = imager.hasConverged()
605 isit = imager.hasConverged()
606 t1 = time.time()
607 casalog.post(
608 "***Time to update mask: " + "%.2f" % (t1 - t0) + " sec",
609 "INFO3",
610 "task_tclean",
611 )
612 while not isit:
613 t0 = time.time()
614 ### sometimes after automasking it does not do anything
615 doneMinor = imager.runMinorCycle()
616 t1 = time.time()
617 casalog.post(
618 "***Time for minor cycle: " + "%.2f" % (t1 - t0) + " sec",
619 "INFO3",
620 "task_tclean",
621 )
623 t0 = time.time()
624 if doneMinor:
625 imager.runMajorCycle()
626 t1 = time.time()
627 casalog.post(
628 "***Time for major cycle: " + "%.2f" % (t1 - t0) + " sec",
629 "INFO3",
630 "task_tclean",
631 )
633 imager.updateMask()
634 t2 = time.time()
635 casalog.post(
636 "***Time to update mask: " + "%.2f" % (t2 - t1) + " sec",
637 "INFO3",
638 "task_tclean",
639 )
640 isit = imager.hasConverged() or (not doneMinor)
642 ## Get summary from iterbot
643 #if type(interactive) != bool:
644 retrec=imager.getSummary(fullsummary);
646 if savemodel!='none' and (interactive==True or usemask=='auto-multithresh' or nsigma>0.0):
647 paramList.resetParameters()
648 if parallel and specmode == "mfs":
649 # For parallel mfs, also needs to reset the parameters for each node
650 imager.resetSaveModelParams(paramList)
651 imager.initializeImagers()
652 imager.predictModel()
654 ## Restore images.
655 if restoration == True:
656 t0 = time.time()
657 imager.restoreImages()
658 t1 = time.time()
659 casalog.post(
660 "***Time for restoring images: " + "%.2f" % (t1 - t0) + " sec",
661 "INFO3",
662 "task_tclean",
663 )
664 if pbcor == True:
665 t0 = time.time()
666 imager.pbcorImages()
667 t1 = time.time()
668 casalog.post(
669 "***Time for pb-correcting images: "
670 + "%.2f" % (t1 - t0)
671 + " sec",
672 "INFO3",
673 "task_tclean",
674 )
675 ######### niter >=0 end if
677 finally:
678 ##close tools
679 # needs to deletools before concat or lock waits for ever
680 if imager != None:
681 imager.deleteTools()
682 if cppparallel:
683 ###release workers back to python mpi control
684 si = synthesisimager()
685 si.releasempi()
686 if pcube:
687 casalog.post("running concatImages ...")
688 casalog.post(
689 "Running virtualconcat (type=%s) of sub-cubes" % concattype,
690 "INFO2",
691 "task_tclean",
692 )
693 imager.concatImages(type=concattype)
694 # CAS-10721
695 # if niter>0 and savemodel != "none":
696 # 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")
698 # Write history at the end, when hopefully all .workdirectory, .work.temp, etc. are gone
699 # from disk, so they won't be picked up. They need time to disappear on NFS or slow hw.
700 try:
701 params = get_func_params(tclean, locals())
702 write_tclean_history(imagename, "tclean", params, casalog)
703 except Exception as exc:
704 casalog.post("Error updating history (logtable): {} ".format(exc), "WARN")
706 return retrec
709##################################################