Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/task_deconvolve.py: 84%
169 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-01 07:19 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-01 07:19 +0000
1import platform
2import time
3import numpy
4import os
5import shutil
6import re
8from casatasks import casalog
10from casatools import image
11from casatasks.private.imagerhelpers.imager_deconvolver import PyDeconvolver
12from casatasks.private.imagerhelpers.input_parameters import ImagerParameters
13from casatasks.private.imagerhelpers.imager_return_dict import ImagingDict
14from casatasks.private.parallel.parallel_task_helper import ParallelTaskHelper
15from .cleanhelper import write_tclean_history, get_func_params
16from casatools import synthesisimager
17ia = image( )
19try:
20 from casampi.MPIEnvironment import MPIEnvironment
21 from casampi import MPIInterface
22 mpi_available = True
23except ImportError:
24 mpi_available = False
26def check_requiredmask_exists(usemask, mask):
27 if usemask != "user": # don't use the mask parameter
28 return
29 if type(mask) is type([]): # mask is an array of values
30 return
31 if mask == "": # mask is an empty string -> no file specified
32 return
33 if "[" in mask: # mask is a region string
34 return
35 if not os.path.exists(mask): # mask is a filename string <- only option left
36 raise RuntimeError("Internal Error: 'mask' parameter specified as a filename '"+mask+"', but no such file exists")
38def check_requiredimgs_exist(imagename, inp):
39 # get the list of images to check for
40 reqims = []
41 if inp['deconvolver'] == 'mtmfs':
42 nterms = inp['nterms']
43 end = nterms*2-1
44 for ttn in range(0, nterms*2-1):
45 reqims.append(imagename + ".psf" + ".tt" + str(ttn))
46 for ttn in range(0, nterms):
47 reqims.append(imagename + ".residual" + ".tt" + str(ttn))
48 else:
49 reqims.append(imagename + ".residual")
50 reqims.append(imagename + ".psf")
52 # find images that exist on disk
53 allfiles = os.listdir(os.path.dirname(os.path.abspath(imagename)))
54 extims = list(filter(lambda im: os.path.exists(im), reqims)) # TODO replace with allfiles
56 # verify required images are available
57 if len(extims) != len(reqims):
58 diffims = list(filter(lambda im: im not in extims, reqims))
59 raise RuntimeError("Internal Error: missing one or more of the required images: " + str(diffims))
61 # check for .pb image in the case that nsigma > 0
62 # see comments on CAS-13144 about casa crashing as to why this check is here
63 if (inp['nsigma'] > 0):
64 reqpb = ".pb" if (inp['deconvolver'] != 'mtmfs') else ".pb.tt0"
65 if (imagename+reqpb not in allfiles):
66 raise RuntimeError("The parameter nsigma>0 ("+str(inp['nsigma'])+") requires a "+reqpb+" image to be available.")
68def check_starmodel_model_collisions(startmodel, imagename, deconvolver):
69 # check for startmodel(s)
70 startmodels = []
71 if type(startmodel) is str:
72 if len(startmodel) > 0:
73 startmodels = [startmodel]
74 else: # if type(startmodel) is list
75 startmodels = startmodel
77 # verify the existance of startmodel(s), and map to imagename.model
78 ttn = 0
79 sm_modim_map = []
80 for sm in startmodels:
81 sm = os.path.normpath(sm)
82 smdir = os.path.dirname(sm)
83 smbase = os.path.basename(sm)
85 # verify startmodel exists
86 # Note: this check should be unneccessary (should be done in cpp), but
87 # current tests indicate that cpp code does not catch this case.
88 if not os.path.exists(sm):
89 raise RuntimeError("Internal Error: parameter startmodel set to \"{0}\" but that file does not exist".format(sm))
91 # get the path to the destination model
92 if ".model" in smbase:
93 ext = re.search(r'(\.model.*)', smbase).group(0)
94 elif deconvolver == 'mtmfs':
95 ext = ".model.tt{0}".format(ttn)
96 ttn += 1
97 else:
98 ext = ".model"
99 modim = os.path.join(smdir, imagename+ext)
100 sm_modim_map.append([sm, modim])
102 # check if both startmodel is set and imagename.model exists
103 # Note: this check should be unneccessary (should be done in cpp), but
104 # current tests indicate that cpp code does not catch this case.
105 if os.path.exists(modim):
106 raise RuntimeError("Internal Error: imagename.model already exists! Either parameter startmodel must not be set ('') or imagename.model ({0}) must not exist.".format(modim) +
107 os.linesep+"\tEither unset startmodel or remove {0} to continue".format(modim))
109 return sm_modim_map
111def deconvolve(
112 ####### Data Selection
113 imagename,#='',
114 startmodel,#='',
116 ####### Deconvolution parameters
117 deconvolver,#='hogbom',
118 scales,#=[],
119 nterms,#=1,
120 smallscalebias,#=0.0
121 # TODO in CAS-13570: uncomment once asp is working
122 # fusedthreshold,#=0.0
123 # largestscale,#=-1
125 ### restoration options
126 restoration,#=True,
127 restoringbeam,#=[],
129 ##### Iteration control
130 niter,#=0,
131 gain,#=0.1,
132 threshold,#=0.0,
133 nsigma,#=0.0
134 interactive,#=False,
135 fullsummary,#=False
136 fastnoise,#=True,
138 ##### (new) Mask parameters
139 usemask,#='user',
140 mask,#='',
141 pbmask,#='',
143 ##### automask by multithresh
144 sidelobethreshold,#=5.0,
145 noisethreshold,#=3.0,
146 lownoisethreshold,#=3.0,
147 negativethreshold,#=0.0,
148 smoothfactor,#=1.0,
149 minbeamfrac,#=0.3,
150 cutthreshold,#=0.01,
151 growiterations,#=100
152 dogrowprune,#=True
153 verbose): #=False
154 """
155 Runs the minor cycle only of tclean.
156 Most of this code is copied directly from tclean.
157 """
159 cppparallel=False
160 decon=None
162 if interactive:
163 # Check for casaviewer, if it does not exist flag it up front for macOS
164 # since casaviewer is no longer provided by default with macOS. Returning
165 # False instead of throwing an exception results in:
166 #
167 # RuntimeError: No active exception to reraise
168 #
169 # from deconvolve run from casashell.
170 try:
171 import casaviewer as __test_casaviewer
172 except:
173 if platform.system( ) == "Darwin":
174 casalog.post(
175 "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol Please restart by setting interactive=F",
176 "WARN",
177 "task_deconvolve",
178 )
179 raise RuntimeError( "casaviewer is no longer available for macOS, for more information see: http://go.nrao.edu/casa-viewer-eol" )
181 try:
183 # discard empty start model strings
184 if type(startmodel) is list:
185 startmodel = list(filter(lambda v: len(v) > 0, startmodel))
187 # clean input
188 inp=locals().copy()
189 inp['msname'] = '' # -> no 'vis' parameter for minor cycle only
190 inp['cycleniter'] = inp['niter']
191 inp['loopgain'] = inp.pop('gain')
192 inp['scalebias'] = inp.pop('smallscalebias')
194 # TODO in CAS-13570: fix asp description and allow asp value once asp is working
195 if deconvolver.lower() == "asp":
196 raise RuntimeError("The "+deconvolver+" deconvolver currently has incorrect end-of-minor-cycle residual calculations and is therefore disabled. Please choose a different deconvolver.")
198 #####################################################
199 #### Construct ImagerParameters
200 #####################################################
202 # Make sure that we have all the necessary images and that the startmodel is valid.
203 # Note: cpp code should check that .residual and .psf exist, but current tests indicate that it doesn't do that.
204 check_requiredmask_exists(usemask, mask)
205 check_requiredimgs_exist(imagename, inp)
206 check_starmodel_model_collisions(startmodel, imagename, deconvolver)
208 # make a list of parameters with defaults from tclean
209 defparm=dict(list(zip(ImagerParameters.__init__.__code__.co_varnames[1:], ImagerParameters.__init__.__defaults__)))
211 ## assign values to the ones passed to deconvolve and if not defined yet in deconvolve...
212 ## assign them the default value of the constructor
213 bparm={k: inp[k] if k in inp else defparm[k] for k in defparm.keys()}
215 #=========================================================
216 ####set the children to load c++ libraries and applicator
217 ### make workers ready for c++ based mpicommands
218 if deconvolver != 'mtmfs': # mtmfs isn't currently parallelized
219 ia.open(imagename+'.psf')
220 isCube=ia.shape()[3] >1 # SynthesisDeconvolver::executeMinorCycle doesn't start mpi without more than one channel
221 ia.done()
222 if mpi_available and MPIEnvironment.is_mpi_enabled and isCube:
223 mint=MPIInterface.MPIInterface()
224 cl=mint.getCluster()
225 cl._cluster.pgc("from casatools import synthesisimager", False)
226 cl._cluster.pgc("si=synthesisimager()", False)
227 cl._cluster.pgc("si.initmpi()", False)
228 cppparallel=True
229 ###ignore chanchunk
230 bparm['chanchunks']=1
232 ## create the parameters list help object
233 paramList=ImagerParameters(**bparm)
235 # Assign cyclethreshold explicitly to threshold
236 threshold = threshold if (type(threshold) == str) else (str(threshold*1000)+'mJy')
237 paramList.setIterPars({'cyclethreshold': threshold, 'cyclethresholdismutable': False})
239 #####################################################
240 #### Run the minor cycle
241 #####################################################
243 iterrec = False
244 isit = 0
245 retrec = {}
247 ## Setup Imager object
248 decon = PyDeconvolver(params=paramList)
250 #################################################
251 #### Setup
252 #################################################
254 ## Init minor cycle elements
255 # print("initializing deconvolver")
256 t0=time.time();
257 decon.initializeDeconvolvers()
258 ####now is the time to check estimated memory
259 decon.estimatememory()
260 ## setup iteration controller
261 decon.initializeIterationControl()
262 t1=time.time();
263 casalog.post("***Time for initializing deconvolver(s): "+"%.2f"%(t1-t0)+" sec", "INFO3", "task_deconvolve");
265 #################################################
266 #### Exec
267 #################################################
269 ## Set up the internal state of the iterater and automask
270 # is this necessary? -> I think so ~bgb200731
271 isit = decon.hasConverged()
272 decon.updateMask()
274 isit = decon.hasConverged() # here in case updateMaskMinor() produces an all-false mask
275 runmin = not isit ## Are minor cycles going to be run or not ? Will the return dictionary have summaryminor or not ?
276 ##print ("Runmin? " , runmin)
277 if not isit:
278 # print("running minor cycle");
279 t0=time.time();
280 decon.runMinorCycle()
281 t1=time.time();
282 casalog.post("***Time for minor cycle: "+"%.2f"%(t1-t0)+" sec", "INFO3", "task_deconvolve");
283 isit = decon.hasConverged() # get the convergence state, to report back to the calling code
286 # Residual image needs to be computed for this to work
287 if niter==0 or runmin==False:
288 id = ImagingDict()
289 retrec1 = id.construct_residual_dict(paramList)
291 ## Get summary from iterbot
292 #if type(interactive) != bool and niter>0:
293 # this requrirment should go...
294 #if niter>0:
295 retrec=decon.getSummary(fullsummary);
297 if niter==0 or runmin==False:
298 retrec['summaryminor'] = retrec1['summaryminor'] #CAS-14184
299 retrec['stopcode'] = retrec1['stopcode']
300 retrec['stopDescription'] = retrec1['stopDescription']
303 #################################################
304 #### Teardown
305 #################################################
307 ## Get records from iterbot, to be used in the next call to deconvolve
308 iterrec = decon.getIterRecords()
310 ## Restore images.
311 if restoration==True:
312 t0=time.time();
313 decon.restoreImages()
314 t1=time.time();
315 casalog.post("***Time for restoring images: "+"%.2f"%(t1-t0)+" sec", "INFO3", "task_deconvolve");
317 ##close tools
318 decon.deleteTools()
320 except Exception as e:
321 casalog.post('Exception from deconvolve : ' + str(e), "SEVERE", "deconvolve")
322 larg = list(e.args)
323 larg[0] = 'Exception from deconvolve : ' + str(larg[0])
324 e.args = tuple(larg)
325 raise
327 finally:
328 if decon != None:
329 decon.deleteTools()
330 if(cppparallel):
331 ###release workers back to python mpi control
332 si=synthesisimager()
333 si.releasempi()
335 # Write history at the end, when hopefully all temp files are gone from disk,
336 # so they won't be picked up. They need time to disappear on NFS or slow hw.
337 # Copied from tclean.
338 try:
339 params = get_func_params(deconvolve, locals())
340 write_tclean_history(imagename, 'deconvolve', params, casalog)
341 except Exception as exc:
342 casalog.post("Error updating history (logtable): {} ".format(exc),'WARN')
344 return retrec