Coverage for /wheeldirectory/casa-6.7.0-12-py3.10.el8/lib/py/lib/python3.10/site-packages/casatasks/private/imagerhelpers/imager_deconvolver.py: 19%
166 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 17:39 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-31 17:39 +0000
1import os
2import math
3import shutil
4import string
5import time
6import re
7import copy
9from casatools import synthesisdeconvolver, iterbotsink, ctsys, table
10from casatasks import casalog
11from casatasks.private.imagerhelpers.summary_minor import SummaryMinor
13ctsys_hostinfo = ctsys.hostinfo
14_tb = table() # TODO is this necessary?
16'''
17A set of helper functions for deconvolve.
19Summary...
21'''
23#############################################
24class PyDeconvolver:
25 def __init__(self,params):
26 ################ Tools
27 self.initDefaults()
29 # Check all input parameters, after partitioning setup.
31 # Imaging/Deconvolution parameters. Same for serial and parallel runs
32 self.alldecpars = params.getDecPars()
33 self.allimpars = params.getImagePars()
34 # Iteration parameters
35 self.iterpars = params.getIterPars() ## Or just params.iterpars
37 # Not necessary for deconvolver:
38 ## self.allselpars = params.getSelPars()
39 ## self.allgridpars = params.getGridPars()
40 ## self.allnormpars = params.getNormPars()
41 ## self.weightpars = params.getWeightPars()
43 ## Number of fields ( main + outliers )
44 self.NF = len(self.allimpars.keys())
45 self.stopMinor = {} ##[0]*self.NF
46 for immod in range(0,self.NF):
47 self.stopMinor[str(immod)]=1.0
48 ## for debug mode automask incrementation only
49 self.ncycle = 0
50 self.initrecs = []
51 self.exrecs = []
53#############################################
54 def initializeDeconvolvers(self):
55 for immod in range(0,self.NF):
56 self.SDtools.append(synthesisdeconvolver())
57 decpars = self.alldecpars[str(immod)]
58 decpars['noRequireSumwt'] = True
59 self.SDtools[immod].setupdeconvolution(decpars=decpars)
61#############################################
62 def initializeIterationControl(self):
63 # note that in CASA5 this is casac.synthesisiterbot
64 self.IBtool = iterbotsink()
65 itbot = self.IBtool.setupiteration(iterpars=self.iterpars)
67#############################################
68 def estimatememory(self):
69 griddermem = 0 # no major cycle memory needed
71 deconmem=0
72 for immod in range(0,self.NF):
73 ims= self.allimpars[str(immod)]['imsize']
74 if(type(ims)==int) :
75 ims=[ims, ims]
76 if(len(ims) ==1):
77 ims.append(ims[0])
78 #print 'shape', self.allimpars[str(immod)]['imsize'], len(ims)
79 #print "DECON mem usage ", self.SDtools[immod].estimatememory(ims)
80 if(len(self.SDtools) > immod):
81 if(self.SDtools != None):
82 deconmem+=self.SDtools[immod].estimatememory(ims)
84 availmem=ctsys_hostinfo()['memory']['available']
85 if((deconmem+griddermem) > 0.8*availmem):
86 casalog.post("Memory available "+str(availmem)+" kB is very close to amount of required memory "+str(deconmem+griddermem)+" kB" , "WARN")
87 else:
88 casalog.post("Memory available "+str(availmem)+" kB and required memory "+str(deconmem+griddermem)+" kB" , "INFO2")
90############################################
91 def restoreImages(self):
92 for immod in range(0,self.NF):
93 self.SDtools[immod].restore()
95#############################################
96 def pbcorImages(self):
97 for immod in range(0,self.NF):
98 self.SDtools[immod].pbcor()
100#############################################
101 def getSummary(self,fullsummary, fignum=1):
102 summ = self.IBtool.getiterationsummary()
103 if ('summaryminor' in summ):
104 summ['summaryminor'] = SummaryMinor.convertMatrix(summ['summaryminor'], fullsummary)
105 return summ
107#############################################
108 def deleteDeconvolvers(self):
109 for immod in range(0,len(self.SDtools)):
110 self.SDtools[immod].done()
112 def deleteIterBot(self):
113 if self.IBtool != None:
114 self.IBtool.done()
116 def initDefaults(self):
117 # Reset globals/members
118 self.NF=1
119 self.stopMinor={'0':1.0} # Flag to call minor cycle for this field or not.
120 self.NN=1
121 self.SItool=None
122 self.SDtools=[]
123 self.PStools=[]
124 self.IBtool=None
126#############################################
128 def deleteTools(self):
129 self.deleteDeconvolvers()
130 self.deleteIterBot()
131 self.initDefaults()
133#############################################
135 def hasConverged(self):
136 # Merge peak-res info from all fields to decide iteration parameters
137 time0=time.time()
138 self.IBtool.resetminorcycleinfo()
139 self.initrecs = []
140 for immod in range(0,self.NF):
141 initrec = self.SDtools[immod].initminorcycle()
142 self.IBtool.mergeinitrecord( initrec );
143 self.initrecs.append(initrec)
145 # Check with the iteration controller about convergence.
146 #print("check convergence")
147 stopflag = self.IBtool.cleanComplete()
148 #print('Converged : ', stopflag)
149 if( stopflag>0 ):
150 stopreasons = ['iteration limit', 'threshold', 'force stop','no change in peak residual across two major cycles', 'peak residual increased by more than 3 times from the previous major cycle','peak residual increased by more than 3 times from the minimum reached','zero mask', 'any combination of n-sigma and other valid exit criterion']
151 casalog.post("Reached global stopping criterion : " + stopreasons[stopflag-1], "INFO")
153 # revert the current automask to the previous one
154 #if self.iterpars['interactive']:
155 for immod in range(0,self.NF):
156 if self.alldecpars[str(immod)]['usemask'].count('auto')>0:
157 prevmask = self.allimpars[str(immod)]['imagename']+'.prev.mask'
158 if os.path.isdir(prevmask):
159 # Try to force rmtree even with an error as an nfs mounted disk gives an error
160 #shutil.rmtree(self.allimpars[str(immod)]['imagename']+'.mask')
161 shutil.rmtree(self.allimpars[str(immod)]['imagename']+'.mask', ignore_errors=True)
162 # For NFS mounted disk it still leave .nfs* file(s)
163 if os.path.isdir(self.allimpars[str(immod)]['imagename']+'.mask'):
164 import glob
165 if glob.glob(self.allimpars[str(immod)]['imagename']+'.mask/.nfs*'):
166 for item in os.listdir(prevmask):
167 src = os.path.join(prevmask,item)
168 dst = os.path.join(self.allimpars[str(immod)]['imagename']+'.mask',item)
169 if os.path.isdir(src):
170 shutil.move(src, dst)
171 else:
172 shutil.copy2(src,dst)
173 shutil.rmtree(prevmask)
174 else:
175 shutil.move(prevmask,self.allimpars[str(immod)]['imagename']+'.mask')
176 casalog.post("[" + str(self.allimpars[str(immod)]['imagename']) + "] : Reverting output mask to one that was last used ", "INFO")
178 casalog.post("***Time taken in checking hasConverged "+str(time.time()-time0), "INFO3")
179 return (stopflag>0)
181#############################################
182 def updateMask(self):
183 # Setup mask for each field ( input mask, and automask )
184 maskchanged = False
185 time0=time.time()
186 for immod in range(0,self.NF):
187 maskchanged = maskchanged | self.SDtools[immod].setupmask()
189 # Run interactive masking (and threshold/niter editors), if interactive=True
190 ig2maskchanged, nil, forcestop = self.runInteractiveGUI2()
191 maskchanged = maskchanged | ig2maskchanged
193 time1=time.time();
194 casalog.post("Time to update mask "+str(time1-time0)+"s", "INFO3")
195 ## Return a flag to say that the mask has changed or not.
196 return maskchanged, forcestop
198#############################################
199 def runInteractiveGUI2(self):
200 maskchanged = False
201 forcestop = True
202 if self.iterpars['interactive'] == True:
203 self.stopMinor = self.IBtool.pauseforinteraction()
204 #print("Actioncodes in python : " , self.stopMinor)
206 for akey in self.stopMinor:
207 if self.stopMinor[akey] < 0:
208 maskchanged = True
209 self.stopMinor[akey] = abs( self.stopMinor[akey] )
211 #Check if force-stop has happened while savemodel != "none".
212 forcestop=True;
213 for akey in self.stopMinor:
214 # Predicting the model requires knowledge about the normalization parameters.
215 # Instead of predicting the model, return the value of forcestop so that the
216 # major cycle has a chance to predict the model.
217 forcestop = forcestop and self.stopMinor[akey]==3
219 #print('Mask changed during interaction : ', maskchanged)
220 return ( maskchanged or forcestop, maskchanged, forcestop )
222#############################################
223 def runMinorCycle(self):
224 self.runMinorCycleCore()
226#############################################
227 def runMinorCycleCore(self):
229 # Set False for release packages.
230 # Only set this to True for testing and debugging automask in parallel mode
231 # since in parallel mode, runtime setting of the enviroment variable
232 # currently does not work.
233 # False = disable always save intermediate images mode
234 alwaysSaveIntermediateImages=False
236 # Get iteration control parameters
237 iterbotrec = self.IBtool.getminorcyclecontrols()
238 #print("In synthdeconv. Minor Cycle controls : ", iterbotrec)
240 self.IBtool.resetminorcycleinfo()
242 #
243 # Run minor cycle
244 self.ncycle+=1
245 self.exrecs = []
246 for immod in range(0,self.NF):
247 if self.stopMinor[str(immod)]<3 :
249 # temporarily disable the check (=> always save the intermediate images
250 if alwaysSaveIntermediateImages or ('SAVE_ALL_RESIMS' in os.environ and os.environ['SAVE_ALL_RESIMS']=="true"):
251 resname = self.allimpars[str(immod)]['imagename']+'.residual'
252 tempresname = self.allimpars[str(immod)]['imagename']+'.inputres'+str(self.ncycle)
253 if os.path.isdir(resname):
254 shutil.copytree(resname, tempresname)
256 exrec = self.SDtools[immod].executeminorcycle( iterbotrecord = iterbotrec )
258 #print('.... iterdone for ', immod, ' : ' , exrec['iterdone'])
259 self.IBtool.mergeexecrecord( exrec )
260 if alwaysSaveIntermediateImages or ('SAVE_ALL_AUTOMASKS' in os.environ and os.environ['SAVE_ALL_AUTOMASKS']=="true"):
261 maskname = self.allimpars[str(immod)]['imagename']+'.mask'
262 tempmaskname = self.allimpars[str(immod)]['imagename']+'.autothresh'+str(self.ncycle)
263 if os.path.isdir(maskname):
264 shutil.copytree(maskname, tempmaskname)
265 self.exrecs.append(exrec)
267 # Some what duplicated as above but keep a copy of the previous mask
268 # for interactive automask to revert to it if the current mask
269 # is not used (i.e. reached deconvolution stopping condition).
270 #if self.iterpars['interactive'] and self.alldecpars[str(immod)]['usemask']=='auto-thresh':
271 if self.alldecpars[str(immod)]['usemask'].count('auto')>0:
272 maskname = self.allimpars[str(immod)]['imagename']+'.mask'
273 prevmaskname=self.allimpars[str(immod)]['imagename']+'.prev.mask'
274 if os.path.isdir(maskname):
275 if os.path.isdir(prevmaskname):
276 shutil.rmtree(prevmaskname)
277 shutil.copytree(maskname, prevmaskname)
279#############################################
280 def getIterRecords(self):
281 return {'initrecs':self.initrecs, 'exrecs':self.exrecs}
283#######################################################
284#######################################################