Commits
Pam Harris authored 530e8194328 Merge
1 1 | from __future__ import absolute_import |
2 2 | import os |
3 3 | import math |
4 4 | import shutil |
5 5 | import string |
6 6 | import time |
7 7 | import re |
8 8 | import copy |
9 9 | from casatasks.private.casa_transition import is_CASA6 |
10 + | |
10 11 | if is_CASA6: |
11 - | from casatools import synthesisimager, synthesisdeconvolver, synthesisnormalizer, iterbotsink, ctsys, table, image |
12 + | from casatools import ( |
13 + | synthesisimager, |
14 + | synthesisdeconvolver, |
15 + | synthesisnormalizer, |
16 + | iterbotsink, |
17 + | ctsys, |
18 + | table, |
19 + | image, |
20 + | ) |
12 21 | from casatasks import casalog |
13 22 | from casatasks.private.imagerhelpers.summary_minor import SummaryMinor |
14 23 | |
15 24 | ctsys_hostinfo = ctsys.hostinfo |
16 25 | _tb = table() |
17 26 | _ia = image() |
18 27 | else: |
19 28 | from taskinit import * |
20 29 | from imagerhelpers.summary_minor import SummaryMinor |
21 30 | |
22 31 | synthesisimager = casac.synthesisimager |
23 32 | synthesisdeconvolver = casac.synthesisdeconvolver |
24 33 | synthesisnormalizer = casac.synthesisnormalizer |
25 34 | # make it look like the CASA6 version even though it's using the CASA5 named tool not present in CASA6 |
26 35 | iterbotsink = casac.synthesisiterbot |
27 36 | |
28 37 | ctsys_hostinfo = casac.cu.hostinfo |
29 38 | |
30 39 | _tb = tb |
31 - | ''' |
40 + | """ |
32 41 | A set of helper functions for tclean. |
33 42 | |
34 43 | Summary... |
35 44 | |
36 - | ''' |
45 + | """ |
37 46 | |
38 47 | ############################################# |
39 48 | class PySynthesisImager: |
40 - | |
41 - | def __init__(self,params): |
49 + | def __init__(self, params): |
42 50 | ################ Tools |
43 51 | self.initDefaults() |
44 52 | |
45 53 | # Check all input parameters, after partitioning setup. |
46 54 | |
47 55 | # Selection Parameters. Dictionary of dictionaries, indexed by 'ms0','ms1',... |
48 56 | self.allselpars = params.getSelPars() |
49 57 | # Imaging/Deconvolution parameters. Same for serial and parallel runs |
50 58 | self.alldecpars = params.getDecPars() |
51 59 | self.allimpars = params.getImagePars() |
52 60 | self.allgridpars = params.getGridPars() |
53 61 | self.allnormpars = params.getNormPars() |
54 62 | self.weightpars = params.getWeightPars() |
55 63 | # Iteration parameters |
56 - | self.iterpars = params.getIterPars() ## Or just params.iterpars |
64 + | self.iterpars = params.getIterPars() ## Or just params.iterpars |
57 65 | |
58 66 | # CFCache params |
59 67 | self.cfcachepars = params.getCFCachePars() |
60 68 | ## Number of fields ( main + outliers ) |
61 69 | self.NF = len(self.allimpars.keys()) |
62 70 | self.stopMinor = {} ##[0]*self.NF |
63 - | for immod in range(0,self.NF): |
64 - | self.stopMinor[str(immod)]=1.0 |
71 + | for immod in range(0, self.NF): |
72 + | self.stopMinor[str(immod)] = 1.0 |
65 73 | ## Number of nodes. This gets set for parallel runs |
66 74 | ## It can also be used serially to process the major cycle in pieces. |
67 - | self.NN = 1 |
75 + | self.NN = 1 |
68 76 | ## for debug mode automask incrementation only |
69 77 | self.ncycle = 0 |
70 78 | # For the nmajor parameter |
71 79 | self.majorCnt = 0 |
72 - | # isvalid = self.checkParameters() |
73 - | # if isvalid==False: |
74 - | # casalog.post('Invalid parameters') |
75 80 | |
76 - | ############################################# |
77 - | # def checkParameters(self): |
78 - | # # Copy the imagename from impars to decpars, for each field. |
79 - | # for immod in range(0,self.NF): |
80 - | # self.alldecpars[str(immod)]['imagename'] = self.allimpars[str(immod)]['imagename'] |
81 - | # return True |
81 + | # isvalid = self.checkParameters() |
82 + | # if isvalid==False: |
83 + | # casalog.post('Invalid parameters') |
82 84 | |
83 - | ############################################# |
84 - | def makeCFCache(self,exists): |
85 + | ############################################# |
86 + | # def checkParameters(self): |
87 + | # # Copy the imagename from impars to decpars, for each field. |
88 + | # for immod in range(0,self.NF): |
89 + | # self.alldecpars[str(immod)]['imagename'] = self.allimpars[str(immod)]['imagename'] |
90 + | # return True |
91 + | |
92 + | ############################################# |
93 + | def makeCFCache(self, exists): |
85 94 | # Make the CFCache and re-load it. The following calls become |
86 95 | # NoOps (in SynthesisImager.cc) if the gridder is not one |
87 96 | # which uses CFCache. |
88 - | if (exists): |
97 + | if exists: |
89 98 | casalog.post("CFCache already exists") |
90 - | else: |
91 - | |
99 + | else: |
92 100 | self.dryGridding(); |
93 101 | self.fillCFCache(); |
94 102 | self.reloadCFCache(); |
95 103 | |
96 - | ############################################# |
97 104 | def initializeImagers(self): |
98 - | |
105 + | |
99 106 | ## Initialize the tool for the current node |
100 107 | self.SItool = synthesisimager() |
101 - | |
108 + | |
102 109 | ## casalog.post('impars ', self.allimpars['0']['specmode'], 'frame', self.allimpars['0']['outframe']) |
103 110 | ## Send in selection parameters for all MSs in the list. |
104 - | for mss in sorted( (self.allselpars).keys() ): |
105 - | # if(self.allimpars['0']['specmode']=='cubedata'): |
106 - | # self.allselpars[mss]['outframe']='Undefined' |
107 - | self.SItool.selectdata( self.allselpars[mss] ) |
108 - | # self.SItool.selectdata( **(self.allselpars[mss]) ) |
111 + | for mss in sorted((self.allselpars).keys()): |
112 + | # if(self.allimpars['0']['specmode']=='cubedata'): |
113 + | # self.allselpars[mss]['outframe']='Undefined' |
114 + | self.SItool.selectdata(self.allselpars[mss]) |
115 + | # self.SItool.selectdata( **(self.allselpars[mss]) ) |
109 116 | |
110 117 | ## For each image-field, define imaging parameters |
111 - | # nimpars = copy.deepcopy(self.allimpars) |
112 - | # for fld in range(0,self.NF): |
113 - | # self.SItool.defineimage( **( nimpars[str(fld)] ) ) |
114 - | |
118 + | # nimpars = copy.deepcopy(self.allimpars) |
119 + | # for fld in range(0,self.NF): |
120 + | # self.SItool.defineimage( **( nimpars[str(fld)] ) ) |
121 + | |
115 122 | # If cfcache directory already exists, assume that it is |
116 123 | # usable and is correct. makeCFCache call then becomes a |
117 124 | # NoOp. |
118 125 | cfCacheName='' |
119 126 | exists=False |
120 127 | if(self.allgridpars['0']['gridder'].startswith('awp')): |
121 128 | cfCacheName=self.allgridpars['0']['cfcache']; |
122 129 | if (cfCacheName == ''): |
123 130 | cfCacheName = self.allimpars['0']['imagename'] + '.cf' |
124 131 | self.allgridpars['0']['cfcache']= cfCacheName |
125 132 | exists = (os.path.exists(cfCacheName) and os.path.isdir(cfCacheName)); |
126 133 | else: |
127 134 | cfCacheName='' |
128 135 | exists=True |
129 136 | |
130 137 | for fld in range(0,self.NF): |
131 138 | # casalog.post("self.allimpars=",self.allimpars,"\n") |
132 - | self.SItool.defineimage( self.allimpars[str(fld)] , self.allgridpars[str(fld)] ) |
139 + | self.SItool.defineimage( |
140 + | self.allimpars[str(fld)], self.allgridpars[str(fld)] |
141 + | ) |
133 142 | |
134 143 | ###for cases when synthesisnormalizer is setup in c++ send the normalizer info |
135 - | ###all images have the same normtype etc..so first one is good enough |
136 - | self.SItool.normalizerinfo(self.allnormpars['0']) |
144 + | ###all images have the same normtype etc..so first one is good enough |
145 + | self.SItool.normalizerinfo(self.allnormpars["0"]) |
137 146 | ###commenting this out so that tuneSelect is done after weighting |
138 147 | ###CAS-11687 |
139 148 | # For cube imaging: align the data selections and image setup |
140 149 | #if self.allimpars['0']['specmode'] != 'mfs' and self.allimpars['0']['specmode'] != 'cubedata': |
141 150 | # self.SItool.tuneselectdata() |
142 151 | ###For cubes create cfcache ahead of each partition trying |
143 152 | ### to create it as it is not multiprocess safe |
144 153 | if("cube" in self.allimpars['0']['specmode']): |
145 154 | self.makeCFCache(exists); |
146 155 | |
147 - | ############################################# |
156 + | ############################################# |
148 157 | |
149 158 | def initializeDeconvolvers(self): |
150 - | for immod in range(0,self.NF): |
151 - | self.SDtools.append(synthesisdeconvolver()) |
152 - | self.SDtools[immod].setupdeconvolution(decpars=self.alldecpars[str(immod)]) |
153 - | |
159 + | for immod in range(0, self.NF): |
160 + | self.SDtools.append(synthesisdeconvolver()) |
161 + | self.SDtools[immod].setupdeconvolution(decpars=self.alldecpars[str(immod)]) |
154 162 | |
155 - | ############################################# |
163 + | ############################################# |
156 164 | ## Overloaded by ParallelCont |
157 165 | def initializeNormalizers(self): |
158 - | for immod in range(0,self.NF): |
166 + | for immod in range(0, self.NF): |
159 167 | self.PStools.append(synthesisnormalizer()) |
160 168 | normpars = self.allnormpars[str(immod)] |
161 169 | self.PStools[immod].setupnormalizer(normpars=normpars) |
162 170 | |
163 - | ############################################# |
171 + | ############################################# |
164 172 | |
165 173 | def initializeIterationControl(self): |
166 174 | # note that in CASA5 this is casac.synthesisiterbot |
167 175 | self.IBtool = iterbotsink() |
168 176 | itbot = self.IBtool.setupiteration(iterpars=self.iterpars) |
169 177 | |
170 - | ############################################# |
178 + | ############################################# |
171 179 | def estimatememory(self): |
172 180 | # casalog.post("MEMORY usage ", self.SItool.estimatememory(), type(self.SItool.estimatememory())) |
173 - | #griddermem=0 |
174 - | if(self.SItool != None): |
175 - | griddermem= self.SItool.estimatememory() |
176 - | deconmem=0 |
177 - | for immod in range(0,self.NF): |
178 - | ims= self.allimpars[str(immod)]['imsize'] |
179 - | if(type(ims)==int) : |
180 - | ims=[ims, ims] |
181 - | if(len(ims) ==1): |
181 + | # griddermem=0 |
182 + | if self.SItool != None: |
183 + | griddermem = self.SItool.estimatememory() |
184 + | deconmem = 0 |
185 + | for immod in range(0, self.NF): |
186 + | ims = self.allimpars[str(immod)]["imsize"] |
187 + | if type(ims) == int: |
188 + | ims = [ims, ims] |
189 + | if len(ims) == 1: |
182 190 | ims.append(ims[0]) |
183 191 | # casalog.post('shape', self.allimpars[str(immod)]['imsize'], len(ims) ) |
184 192 | # casalog.post("DECON mem usage ", self.SDtools[immod].estimatememory(ims)) |
185 - | if(len(self.SDtools) > immod): |
186 - | if(self.SDtools != None): |
187 - | deconmem+=self.SDtools[immod].estimatememory(ims) |
188 - | availmem=ctsys_hostinfo()['memory']['available'] |
189 - | if((deconmem+griddermem) > 0.8*availmem): |
190 - | casalog.post("Memory available "+str(availmem)+" kB is very close to amount of required memory "+str(deconmem+griddermem)+" kB" , "WARN") |
193 + | if len(self.SDtools) > immod: |
194 + | if self.SDtools != None: |
195 + | deconmem += self.SDtools[immod].estimatememory(ims) |
196 + | availmem = ctsys_hostinfo()["memory"]["available"] |
197 + | if (deconmem + griddermem) > 0.8 * availmem: |
198 + | casalog.post( |
199 + | "Memory available " |
200 + | + str(availmem) |
201 + | + " kB is very close to amount of required memory " |
202 + | + str(deconmem + griddermem) |
203 + | + " kB", |
204 + | "WARN", |
205 + | ) |
191 206 | else: |
192 - | casalog.post("Memory available "+str(availmem)+" kB and required memory "+str(deconmem+griddermem)+" kB" , "INFO2") |
193 - | ############################################ |
207 + | casalog.post( |
208 + | "Memory available " |
209 + | + str(availmem) |
210 + | + " kB and required memory " |
211 + | + str(deconmem + griddermem) |
212 + | + " kB", |
213 + | "INFO2", |
214 + | ) |
215 + | |
216 + | ############################################ |
194 217 | def restoreImages(self): |
195 - | for immod in range(0,self.NF): |
196 - | self.SDtools[immod].restore() |
218 + | for immod in range(0, self.NF): |
219 + | self.SDtools[immod].restore() |
197 220 | |
198 - | ############################################# |
221 + | ############################################# |
199 222 | def pbcorImages(self): |
200 - | for immod in range(0,self.NF): |
201 - | self.SDtools[immod].pbcor() |
223 + | for immod in range(0, self.NF): |
224 + | self.SDtools[immod].pbcor() |
202 225 | |
203 - | ############################################# |
226 + | ############################################# |
204 227 | |
205 228 | def getSummary(self,fullsummary,fignum=1): |
206 229 | summ = self.IBtool.getiterationsummary() |
207 230 | casalog.post('getSummary call: fullsummary='+str(fullsummary)) |
208 231 | if ('stopcode' in summ): |
209 232 | summ['stopDescription'] = self.getStopDescription(summ['stopcode']) |
210 233 | if ('summaryminor' in summ): |
211 234 | summ['summaryminor'] = SummaryMinor.convertMatrix(summ['summaryminor'],fullsummary) |
212 235 | #self.plotReport( summ, fignum ) |
236 + | |
213 237 | return summ |
214 238 | |
215 - | ############################################# |
239 + | ############################################# |
216 240 | def deleteImagers(self): |
217 241 | if self.SItool != None: |
218 242 | self.SItool.done() |
219 - | self.SItool=None |
243 + | self.SItool = None |
220 244 | |
221 245 | def deleteDeconvolvers(self): |
222 - | for immod in range(0,len(self.SDtools)): |
223 - | self.SDtools[immod].done() |
246 + | for immod in range(0, len(self.SDtools)): |
247 + | self.SDtools[immod].done() |
224 248 | |
225 249 | def deleteNormalizers(self): |
226 - | for immod in range(0,len(self.PStools)): |
250 + | for immod in range(0, len(self.PStools)): |
227 251 | self.PStools[immod].done() |
228 252 | |
229 253 | def deleteIterBot(self): |
230 - | if self.IBtool != None: |
231 - | self.IBtool.done() |
254 + | if self.IBtool != None: |
255 + | self.IBtool.done() |
232 256 | |
233 257 | def deleteCluster(self): |
234 258 | # casalog.post('no cluster to delete') |
235 259 | return |
236 260 | |
237 261 | def deleteWorkDir(self): |
238 262 | # No .workdirectory to delete |
239 263 | return |
240 264 | |
241 265 | def initDefaults(self): |
242 266 | # Reset globals/members |
243 - | self.NF=1 |
244 - | self.stopMinor={'0':1.0} # Flag to call minor cycle for this field or not. |
245 - | self.NN=1 |
246 - | self.SItool=None |
247 - | self.SDtools=[] |
248 - | self.PStools=[] |
249 - | self.IBtool=None |
250 - | |
251 - | ############################################# |
267 + | self.NF = 1 |
268 + | self.stopMinor = {"0": 1.0} # Flag to call minor cycle for this field or not. |
269 + | self.NN = 1 |
270 + | self.SItool = None |
271 + | self.SDtools = [] |
272 + | self.PStools = [] |
273 + | self.IBtool = None |
274 + | |
275 + | ############################################# |
252 276 | |
253 277 | def deleteTools(self): |
254 - | self.deleteImagers() |
255 - | self.deleteDeconvolvers() |
256 - | self.deleteNormalizers() |
257 - | self.deleteIterBot() |
258 - | self.deleteWorkDir() |
259 - | self.initDefaults() |
260 - | self.deleteCluster() |
278 + | self.deleteImagers() |
279 + | self.deleteDeconvolvers() |
280 + | self.deleteNormalizers() |
281 + | self.deleteIterBot() |
282 + | self.deleteWorkDir() |
283 + | self.initDefaults() |
284 + | self.deleteCluster() |
261 285 | |
262 - | ############################################# |
286 + | ############################################# |
263 287 | |
264 288 | def getStopDescription(self, stopflag): |
265 289 | stopreasons = [ |
266 - | 'iteration limit', # 1 |
267 - | 'threshold', # 2 |
268 - | 'force stop', # 3 |
269 - | 'no change in peak residual across two major cycles', # 4 |
270 - | 'peak residual increased by more than 3 times from the previous major cycle', # 5 |
271 - | 'peak residual increased by more than 3 times from the minimum reached', # 6 |
272 - | 'zero mask', # 7 |
273 - | 'any combination of n-sigma and other valid exit criterion', # 8 |
274 - | 'reached nmajor' # 9 |
290 + | "iteration limit", # 1 |
291 + | "threshold", # 2 |
292 + | "force stop", # 3 |
293 + | "no change in peak residual across two major cycles", # 4 |
294 + | "peak residual increased by more than 3 times from the previous major cycle", # 5 |
295 + | "peak residual increased by more than 3 times from the minimum reached", # 6 |
296 + | "zero mask", # 7 |
297 + | "any combination of n-sigma and other valid exit criterion", # 8 |
298 + | "reached nmajor", # 9 |
275 299 | ] |
276 - | if (stopflag > 0): |
277 - | return stopreasons[stopflag-1] |
300 + | if stopflag > 0: |
301 + | return stopreasons[stopflag - 1] |
278 302 | return None |
279 303 | |
280 304 | def hasConverged(self): |
281 305 | # Merge peak-res info from all fields to decide iteration parameters |
282 - | time0=time.time() |
283 - | self.IBtool.resetminorcycleinfo() |
284 - | for immod in range(0,self.NF): |
285 - | initrec = self.SDtools[immod].initminorcycle() |
286 - | #print('INIT Minor cycle dict {}'.format(initrec)) |
287 - | self.IBtool.mergeinitrecord( initrec ); |
288 - | |
289 - | # # Run interactive masking (and threshold/niter editors) |
290 - | # self.runInteractiveGUI2() |
291 - | |
292 - | # Check with the iteration controller about convergence. |
293 - | reachedNmajor = (self.iterpars['nmajor'] >= 0 and self.majorCnt >= self.iterpars['nmajor']) |
294 - | stopflag = self.IBtool.cleanComplete(reachedMajorLimit=reachedNmajor) |
295 - | if( stopflag>0 ): |
296 - | casalog.post("Reached global stopping criterion : " + self.getStopDescription(stopflag), "INFO") |
297 - | |
298 - | # revert the current automask to the previous one |
299 - | #if self.iterpars['interactive']: |
300 - | for immod in range(0,self.NF): |
301 - | if (self.alldecpars[str(immod)]['usemask'].count('auto')>0) : |
302 - | prevmask = self.allimpars[str(immod)]['imagename']+'.prev.mask' |
303 - | if os.path.isdir(prevmask): |
304 - | # Try to force rmtree even with an error as an nfs mounted disk gives an error |
305 - | #shutil.rmtree(self.allimpars[str(immod)]['imagename']+'.mask') |
306 - | shutil.rmtree(self.allimpars[str(immod)]['imagename']+'.mask', ignore_errors=True) |
307 - | # For NFS mounted disk it still leave .nfs* file(s) |
308 - | if os.path.isdir(self.allimpars[str(immod)]['imagename']+'.mask'): |
309 - | import glob |
310 - | if glob.glob(self.allimpars[str(immod)]['imagename']+'.mask/.nfs*'): |
311 - | for item in os.listdir(prevmask): |
312 - | src = os.path.join(prevmask,item) |
313 - | dst = os.path.join(self.allimpars[str(immod)]['imagename']+'.mask',item) |
314 - | if os.path.isdir(src): |
315 - | shutil.move(src, dst) |
316 - | else: |
317 - | shutil.copy2(src,dst) |
318 - | shutil.rmtree(prevmask) |
319 - | else: |
320 - | shutil.move(prevmask,self.allimpars[str(immod)]['imagename']+'.mask') |
321 - | casalog.post("[" + str(self.allimpars[str(immod)]['imagename']) + "] : Reverting output mask to one that was last used ", "INFO") |
322 - | casalog.post("***Time taken in checking hasConverged "+str(time.time()-time0), "INFO3") |
323 - | return (stopflag>0) |
306 + | time0 = time.time() |
307 + | self.IBtool.resetminorcycleinfo() |
308 + | for immod in range(0, self.NF): |
309 + | initrec = self.SDtools[immod].initminorcycle() |
310 + | # print('INIT Minor cycle dict {}'.format(initrec)) |
311 + | self.IBtool.mergeinitrecord(initrec) |
312 + | |
313 + | # # Run interactive masking (and threshold/niter editors) |
314 + | # self.runInteractiveGUI2() |
315 + | |
316 + | # Check with the iteration controller about convergence. |
317 + | reachedNmajor = ( |
318 + | self.iterpars["nmajor"] >= 0 and self.majorCnt >= self.iterpars["nmajor"] |
319 + | ) |
320 + | stopflag = self.IBtool.cleanComplete(reachedMajorLimit=reachedNmajor) |
321 + | if stopflag > 0: |
322 + | casalog.post( |
323 + | "Reached global stopping criterion : " |
324 + | + self.getStopDescription(stopflag), |
325 + | "INFO", |
326 + | ) |
327 + | |
328 + | # revert the current automask to the previous one |
329 + | # if self.iterpars['interactive']: |
330 + | for immod in range(0, self.NF): |
331 + | if self.alldecpars[str(immod)]["usemask"].count("auto") > 0: |
332 + | prevmask = self.allimpars[str(immod)]["imagename"] + ".prev.mask" |
333 + | if os.path.isdir(prevmask): |
334 + | # Try to force rmtree even with an error as an nfs mounted disk gives an error |
335 + | # shutil.rmtree(self.allimpars[str(immod)]['imagename']+'.mask') |
336 + | shutil.rmtree( |
337 + | self.allimpars[str(immod)]["imagename"] + ".mask", |
338 + | ignore_errors=True, |
339 + | ) |
340 + | # For NFS mounted disk it still leave .nfs* file(s) |
341 + | if os.path.isdir( |
342 + | self.allimpars[str(immod)]["imagename"] + ".mask" |
343 + | ): |
344 + | import glob |
345 + | |
346 + | if glob.glob( |
347 + | self.allimpars[str(immod)]["imagename"] + ".mask/.nfs*" |
348 + | ): |
349 + | for item in os.listdir(prevmask): |
350 + | src = os.path.join(prevmask, item) |
351 + | dst = os.path.join( |
352 + | self.allimpars[str(immod)]["imagename"] |
353 + | + ".mask", |
354 + | item, |
355 + | ) |
356 + | if os.path.isdir(src): |
357 + | shutil.move(src, dst) |
358 + | else: |
359 + | shutil.copy2(src, dst) |
360 + | shutil.rmtree(prevmask) |
361 + | else: |
362 + | shutil.move( |
363 + | prevmask, |
364 + | self.allimpars[str(immod)]["imagename"] + ".mask", |
365 + | ) |
366 + | casalog.post( |
367 + | "[" |
368 + | + str(self.allimpars[str(immod)]["imagename"]) |
369 + | + "] : Reverting output mask to one that was last used ", |
370 + | "INFO", |
371 + | ) |
372 + | casalog.post( |
373 + | "***Time taken in checking hasConverged " + str(time.time() - time0), |
374 + | "INFO3", |
375 + | ) |
376 + | return stopflag > 0 |
324 377 | |
325 - | ############################################# |
378 + | ############################################# |
326 379 | def updateMask(self): |
327 380 | # Setup mask for each field ( input mask, and automask ) |
328 381 | maskchanged = False |
329 - | time0=time.time() |
330 - | for immod in range(0,self.NF): |
331 - | maskchanged = maskchanged | self.SDtools[immod].setupmask() |
332 - | |
382 + | time0 = time.time() |
383 + | for immod in range(0, self.NF): |
384 + | maskchanged = maskchanged | self.SDtools[immod].setupmask() |
385 + | |
333 386 | # Run interactive masking (and threshold/niter editors), if interactive=True |
334 387 | maskchanged = maskchanged | self.runInteractiveGUI2() |
335 388 | |
336 - | time1=time.time(); |
337 - | casalog.post("Time to update mask "+str(time1-time0)+"s", "INFO3") |
389 + | time1 = time.time() |
390 + | casalog.post("Time to update mask " + str(time1 - time0) + "s", "INFO3") |
338 391 | ## Return a flag to say that the mask has changed or not. |
339 392 | return maskchanged |
340 393 | |
341 - | ############################################# |
394 + | ############################################# |
342 395 | def runInteractiveGUI2(self): |
343 396 | maskchanged = False |
344 397 | forcestop = True |
345 - | if self.iterpars['interactive'] == True: |
398 + | if self.iterpars["interactive"] == True: |
346 399 | self.stopMinor = self.IBtool.pauseforinteraction() |
347 400 | # casalog.post("Actioncodes in python : " , self.stopMinor) |
348 401 | |
349 402 | for akey in self.stopMinor: |
350 403 | if self.stopMinor[akey] < 0: |
351 404 | maskchanged = True |
352 - | self.stopMinor[akey] = abs( self.stopMinor[akey] ) |
405 + | self.stopMinor[akey] = abs(self.stopMinor[akey]) |
353 406 | |
354 - | #Check if force-stop has happened while savemodel != "none". |
407 + | # Check if force-stop has happened while savemodel != "none". |
355 408 | # If so, warn the user that unless the Last major cycle has happened, |
356 409 | # the model won't have been written into the MS, and to do a 'predict' run. |
357 - | forcestop=True; |
410 + | forcestop = True |
358 411 | for akey in self.stopMinor: |
359 - | forcestop = forcestop and self.stopMinor[akey]==3 |
412 + | forcestop = forcestop and self.stopMinor[akey] == 3 |
360 413 | |
361 - | if self.iterpars['savemodel'] != "none": |
362 - | if forcestop==True: |
414 + | if self.iterpars["savemodel"] != "none": |
415 + | if forcestop == True: |
363 416 | self.predictModel() |
364 - | #if self.iterpars['savemodel'] == "modelcolumn": |
417 + | # if self.iterpars['savemodel'] == "modelcolumn": |
365 418 | # wstr = "Saving model column" |
366 - | #else: |
419 + | # else: |
367 420 | # wstr = "Saving virtual model" |
368 - | #casalog.post("Model visibilities may not have been saved in the MS even though you have asked for it. Please check the logger for the phrases 'Run (Last) Major Cycle' and '" + wstr +"'. If these do not appear, then please save the model via a separate tclean run with niter=0,calcres=F,calcpsf=F. It will pick up the existing model from disk and save/predict it. Reason for this : For performance reasons model visibilities are saved only in the last major cycle. If the X button on the interactive GUI is used to terminate a run before this automatically detected 'last' major cycle, the model isn't written. However, a subsequent tclean run as described above will predict and save the model. ","WARN") |
421 + | # casalog.post("Model visibilities may not have been saved in the MS even though you have asked for it. Please check the logger for the phrases 'Run (Last) Major Cycle' and '" + wstr +"'. If these do not appear, then please save the model via a separate tclean run with niter=0,calcres=F,calcpsf=F. It will pick up the existing model from disk and save/predict it. Reason for this : For performance reasons model visibilities are saved only in the last major cycle. If the X button on the interactive GUI is used to terminate a run before this automatically detected 'last' major cycle, the model isn't written. However, a subsequent tclean run as described above will predict and save the model. ","WARN") |
369 422 | |
370 423 | # casalog.post('Mask changed during interaction : ', maskchanged) |
371 - | return ( maskchanged or forcestop ) |
424 + | return maskchanged or forcestop |
372 425 | |
373 - | ############################################# |
426 + | ############################################# |
374 427 | def makePSF(self): |
375 428 | |
376 429 | self.makePSFCore() |
377 430 | divideInPython=self.allimpars['0']['specmode'] == 'mfs' or self.allimpars['0']['deconvolver'] == 'mtmfs' |
378 431 | ### Gather PSFs (if needed) and normalize by weight |
379 - | for immod in range(0,self.NF): |
380 - | #for cube normalization is done in C++ |
381 - | if divideInPython : |
382 - | self.PStools[immod].gatherpsfweight() |
432 + | for immod in range(0, self.NF): |
433 + | # for cube normalization is done in C++ |
434 + | if divideInPython: |
435 + | self.PStools[immod].gatherpsfweight() |
383 436 | self.PStools[immod].dividepsfbyweight() |
384 437 | if self.SDtools != []: |
385 438 | if immod <= len(self.SDtools) - 1: |
386 439 | self.SDtools[immod].checkrestoringbeam() |
387 440 | |
388 - | |
389 - | ############################################# |
441 + | ############################################# |
390 442 | def calcVisAppSens(self): |
391 443 | |
392 444 | return self.SItool.apparentsens() |
393 445 | |
394 - | |
395 - | ############################################# |
446 + | ############################################# |
396 447 | |
397 448 | def runMajorCycle(self, isCleanCycle=True): |
398 449 | # @param isCleanCycle: true if this is part of the major/minor cleaning loop, false if this is being used for some other purpose (such as generating the residual image) |
399 450 | if self.IBtool != None: |
400 - | lastcycle = (self.IBtool.cleanComplete(lastcyclecheck=True) > 0) |
451 + | lastcycle = self.IBtool.cleanComplete(lastcyclecheck=True) > 0 |
401 452 | else: |
402 453 | lastcycle = True |
403 454 | divideInPython=self.allimpars['0']['specmode'] == 'mfs' or self.allimpars['0']['deconvolver'] == 'mtmfs' |
404 455 | ##norm is done in C++ for cubes |
405 - | if not divideInPython : |
456 + | if not divideInPython: |
406 457 | self.runMajorCycleCore(lastcycle) |
407 458 | if isCleanCycle: |
408 459 | self.majorCnt += 1 |
409 460 | if self.IBtool != None: |
410 461 | self.IBtool.endmajorcycle() |
411 462 | return |
412 - | |
413 - | for immod in range(0,self.NF): |
463 + | |
464 + | for immod in range(0, self.NF): |
414 465 | self.PStools[immod].dividemodelbyweight() |
415 - | self.PStools[immod].scattermodel() |
466 + | self.PStools[immod].scattermodel() |
416 467 | self.runMajorCycleCore(lastcycle) |
417 468 | if isCleanCycle: |
418 469 | self.majorCnt += 1 |
419 470 | |
420 471 | if self.IBtool != None: |
421 472 | self.IBtool.endmajorcycle() |
422 473 | ### Gather residuals (if needed) and normalize by weight |
423 - | for immod in range(0,self.NF): |
424 - | self.PStools[immod].gatherresidual() |
474 + | for immod in range(0, self.NF): |
475 + | self.PStools[immod].gatherresidual() |
425 476 | self.PStools[immod].divideresidualbyweight() |
426 477 | self.PStools[immod].multiplymodelbyweight() |
427 478 | |
428 - | ############################################# |
479 + | ############################################# |
429 480 | def predictModel(self): |
430 - | for immod in range(0,self.NF): |
481 + | for immod in range(0, self.NF): |
431 482 | self.PStools[immod].dividemodelbyweight() |
432 - | self.PStools[immod].scattermodel() |
483 + | self.PStools[immod].scattermodel() |
433 484 | |
434 485 | self.predictModelCore() |
435 - | ###return the model images back to whatever state they were |
436 - | for immod in range(0,self.NF): |
486 + | ###return the model images back to whatever state they were |
487 + | for immod in range(0, self.NF): |
437 488 | self.PStools[immod].multiplymodelbyweight() |
438 - | ## self.SItool.predictmodel(); |
439 489 | |
440 - | ############################################# |
490 + | ## self.SItool.predictmodel(); |
491 + | |
492 + | ############################################# |
441 493 | def dryGridding(self): |
442 - | self.SItool.drygridding(**(self.cfcachepars)) ; |
443 - | ############################################# |
444 - | ## Overloaded for parallel runs |
494 + | self.SItool.drygridding(**(self.cfcachepars)) |
495 + | |
496 + | ############################################# |
497 + | ## Overloaded for parallel runs |
445 498 | def fillCFCache(self): |
446 - | cfcName = self.allgridpars['0']['cfcache']; |
447 - | cflist=[]; |
448 - | if (not (cfcName == '')): |
449 - | cflist=[f for f in os.listdir(cfcName) if re.match(r'CFS*', f)]; |
450 - | #cflist = ["CFS_0_0_CF_0_0_0.im"]; |
451 - | self.cfcachepars['cflist']=cflist; |
452 - | |
453 - | #self.SItool.fillcfcache(**(self.cfcachepars), self.allgridpars['0']['gridder'],cfcName); |
454 - | |
455 - | self.SItool.fillcfcache(cflist, self.allgridpars['0']['gridder'], |
456 - | cfcName, |
457 - | self.allgridpars['0']['psterm'], |
458 - | self.allgridpars['0']['aterm'], |
459 - | self.allgridpars['0']['conjbeams']); |
460 - | |
461 - | ############################################# |
499 + | cfcName = self.allgridpars["0"]["cfcache"] |
500 + | cflist = [] |
501 + | if not (cfcName == ""): |
502 + | cflist = [f for f in os.listdir(cfcName) if re.match(r"CFS*", f)] |
503 + | # cflist = ["CFS_0_0_CF_0_0_0.im"]; |
504 + | self.cfcachepars["cflist"] = cflist |
505 + | |
506 + | # self.SItool.fillcfcache(**(self.cfcachepars), self.allgridpars['0']['gridder'],cfcName); |
507 + | |
508 + | self.SItool.fillcfcache( |
509 + | cflist, |
510 + | self.allgridpars["0"]["gridder"], |
511 + | cfcName, |
512 + | self.allgridpars["0"]["psterm"], |
513 + | self.allgridpars["0"]["aterm"], |
514 + | self.allgridpars["0"]["conjbeams"], |
515 + | ) |
516 + | |
517 + | ############################################# |
462 518 | def reloadCFCache(self): |
463 - | self.SItool.reloadcfcache(); |
519 + | self.SItool.reloadcfcache() |
464 520 | |
465 - | ############################################# |
521 + | ############################################# |
466 522 | def makePB(self): |
467 523 | ###for cube standard gridder pb is made in c++ with psf |
468 - | if(not("stand" in self.allgridpars['0']['gridder'] and "cube" in self.allimpars['0']['specmode'])): |
524 + | if not ( |
525 + | "stand" in self.allgridpars["0"]["gridder"] |
526 + | and "cube" in self.allimpars["0"]["specmode"] |
527 + | ): |
469 528 | self.makePBCore() |
470 - | for immod in range(0,self.NF): |
471 - | self.PStools[immod].normalizeprimarybeam() |
529 + | for immod in range(0, self.NF): |
530 + | self.PStools[immod].normalizeprimarybeam() |
472 531 | |
473 - | ############################################# |
532 + | ############################################# |
474 533 | def makePBCore(self): |
475 534 | self.SItool.makepb() |
476 535 | |
477 - | ############################################# |
536 + | ############################################# |
478 537 | def checkPB(self): |
479 538 | """Checks for common problem cases in the .pb image""" |
480 539 | if self.SItool is None: |
481 540 | # Seems to be None for specmode='mfs', parallel=True |
482 541 | return |
483 542 | |
484 543 | import numpy as np |
485 - | facetIdx = 0 # TODO iterate over facets |
544 + | |
545 + | facetIdx = 0 # TODO iterate over facets |
486 546 | imagename = self.SItool.getImageName(facetIdx, "PB") |
487 547 | _ia.open(imagename) |
488 548 | # Case 1: non-zeroes on edge of .pb |
489 549 | pixelVals = _ia.getregion().copy() |
490 - | pixelVals[1:-2][1:-2] = 0 # zero out everything that isn't at the edge of 'right ascension' and 'declination' indexes |
550 + | pixelVals[1:-2][ |
551 + | 1:-2 |
552 + | ] = 0 # zero out everything that isn't at the edge of 'right ascension' and 'declination' indexes |
491 553 | if pixelVals.max() > 0: |
492 554 | idx = np.unravel_index([pixelVals.argmax()], pixelVals.shape) |
493 - | idx = [x[0] for x in idx] # (array([296]), array([147]), array([0]), array([0])) --> [296, 147, 0, 0] |
494 - | casalog.post(f"Warning! Non-zero values at the edge of the .pb image can cause unexpected aliasing effects! (found value {pixelVals.max()} at index {idx})", "WARN") |
555 + | idx = [ |
556 + | x[0] for x in idx |
557 + | ] # (array([296]), array([147]), array([0]), array([0])) --> [296, 147, 0, 0] |
558 + | casalog.post( |
559 + | f"Warning! Non-zero values at the edge of the .pb image can cause unexpected aliasing effects! (found value {pixelVals.max()} at index {idx})", |
560 + | "WARN", |
561 + | ) |
495 562 | # release the image |
496 563 | _ia.close() |
497 564 | _ia.done() |
498 565 | |
499 - | ############################################# |
566 + | ############################################# |
500 567 | def makeSdImage(self): |
501 568 | self.makeSdImageCore() |
502 - | for immod in range(0,self.NF): |
503 - | self.PStools[immod].gatherresidual() |
569 + | for immod in range(0, self.NF): |
570 + | self.PStools[immod].gatherresidual() |
504 571 | self.PStools[immod].divideresidualbyweight() |
505 572 | |
506 - | ############################################# |
573 + | ############################################# |
507 574 | def makeSdPSF(self): |
508 575 | self.makeSdPSFCore() |
509 - | for immod in range(0,self.NF): |
510 - | self.PStools[immod].gatherresidual() |
576 + | for immod in range(0, self.NF): |
577 + | self.PStools[immod].gatherresidual() |
511 578 | self.PStools[immod].dividepsfbyweight() |
512 579 | |
513 - | ############################################# |
580 + | ############################################# |
514 581 | def makeSdImageCore(self): |
515 582 | self.SItool.makesdimage() |
516 583 | |
517 - | ############################################# |
584 + | ############################################# |
518 585 | def makeSdPSFCore(self): |
519 586 | self.SItool.makesdpsf() |
520 587 | |
521 - | ############################################# |
522 - | def makeImage(self, imagetype='observed', image='', compleximage='', imagefieldid=0): |
588 + | ############################################# |
589 + | def makeImage( |
590 + | self, imagetype="observed", image="", compleximage="", imagefieldid=0 |
591 + | ): |
523 592 | """ |
524 - | This should replace makeSDImage, makeSDPSF and makePSF |
593 + | This should replace makeSDImage, makeSDPSF and makePSF |
525 594 | etc in the long run |
526 595 | But for now you can do the following images i.e string recognized by type |
527 - | "observed", "model", "corrected", "psf", "residual", "singledish-observed", |
596 + | "observed", "model", "corrected", "psf", "residual", "singledish-observed", |
528 597 | "singledish", "coverage", "holography", "holography-observed" |
529 598 | For holography the FTmachine should be SDGrid and the baselines |
530 599 | selected should be those that are pointed up with the antenna which is rastering. |
531 600 | """ |
532 601 | self.SItool.makeimage(imagetype, image, compleximage, imagefieldid) |
533 - | ############################################# |
534 602 | |
535 - | ## Overloaded for parallel runs |
603 + | ############################################# |
604 + | |
605 + | ## Overloaded for parallel runs |
536 606 | def setWeighting(self): |
537 607 | ## Set weighting parameters, and all pars common to all fields. |
538 - | self.SItool.setweighting( **(self.weightpars) ) |
608 + | self.SItool.setweighting(**(self.weightpars)) |
539 609 | ##moved the tuneselect after weighting so that |
540 610 | ##the weight densities use all the data selected CAS-11687 |
541 611 | ###For cube imaging: align the data selections and image setup |
542 612 | ### the tuneSelect is now done in C++ CubeMajorCycleAlgorith.cc |
543 - | #if self.allimpars['0']['specmode'] != 'mfs' and self.allimpars['0']['specmode'] != 'cubedata': |
613 + | # if self.allimpars['0']['specmode'] != 'mfs' and self.allimpars['0']['specmode'] != 'cubedata': |
544 614 | # self.SItool.tuneselectdata() |
545 - | |
615 + | |
546 616 | # casalog.post("get set density from python") |
547 617 | # self.SItool.getweightdensity() |
548 618 | # self.SItool.setweightdensity() |
549 619 | |
550 - | |
551 - | ############################################# |
552 - | ## Overloaded for parallel runs |
620 + | ############################################# |
621 + | ## Overloaded for parallel runs |
553 622 | def makePSFCore(self): |
554 623 | self.SItool.makepsf() |
555 - | ############################################# |
556 - | ## Overloaded for parallel runs |
624 + | |
625 + | ############################################# |
626 + | ## Overloaded for parallel runs |
557 627 | def runMajorCycleCore(self, lastcycle): |
558 - | controldict={'lastcycle':lastcycle} |
559 - | if(('0' in self.alldecpars) and ('usemask' in self.alldecpars['0'])): |
560 - | controldict['usemask']=self.alldecpars['0']['usemask'] |
628 + | controldict = {"lastcycle": lastcycle} |
629 + | if ("0" in self.alldecpars) and ("usemask" in self.alldecpars["0"]): |
630 + | controldict["usemask"] = self.alldecpars["0"]["usemask"] |
561 631 | self.SItool.executemajorcycle(controls=controldict) |
562 - | ############################################# |
563 - | ## Overloaded for parallel runs |
632 + | |
633 + | ############################################# |
634 + | ## Overloaded for parallel runs |
564 635 | def predictModelCore(self): |
565 636 | self.SItool.predictmodel() |
566 - | ############################################# |
637 + | |
638 + | ############################################# |
567 639 | |
568 640 | def runMinorCycle(self): |
569 641 | return self.runMinorCycleCore() |
570 - | ############################################# |
642 + | |
643 + | ############################################# |
571 644 | |
572 645 | def runMinorCycleCore(self): |
573 646 | |
574 - | # Set False for release packages. |
647 + | # Set False for release packages. |
575 648 | # Only set this to True for testing and debugging automask in parallel mode |
576 649 | # since in parallel mode, runtime setting of the enviroment variable |
577 650 | # currently does not work. |
578 651 | # False = disable always save intermediate images mode |
579 - | alwaysSaveIntermediateImages=False |
652 + | alwaysSaveIntermediateImages = False |
580 653 | |
581 654 | # Get iteration control parameters |
582 655 | iterbotrec = self.IBtool.getminorcyclecontrols() |
583 656 | |
584 657 | # TT debug - comment out after debugging.... |
585 658 | casalog.post("Minor Cycle controls : " + str(iterbotrec)) |
586 659 | |
587 - | self.IBtool.resetminorcycleinfo() |
660 + | self.IBtool.resetminorcycleinfo() |
588 661 | |
589 662 | # |
590 663 | # Run minor cycle |
591 - | self.ncycle+=1 |
592 - | retval=False |
593 - | for immod in range(0,self.NF): |
594 - | if self.stopMinor[str(immod)]<3 : |
664 + | self.ncycle += 1 |
665 + | retval = False |
666 + | for immod in range(0, self.NF): |
667 + | if self.stopMinor[str(immod)] < 3: |
595 668 | |
596 669 | # temporarily disable the check (=> always save the intermediate images |
597 - | if alwaysSaveIntermediateImages or ('SAVE_ALL_RESIMS' in os.environ and os.environ['SAVE_ALL_RESIMS']=="true"): |
598 - | resname = self.allimpars[str(immod)]['imagename']+'.residual' |
599 - | tempresname = self.allimpars[str(immod)]['imagename']+'.inputres'+str(self.ncycle) |
670 + | if alwaysSaveIntermediateImages or ( |
671 + | "SAVE_ALL_RESIMS" in os.environ |
672 + | and os.environ["SAVE_ALL_RESIMS"] == "true" |
673 + | ): |
674 + | resname = self.allimpars[str(immod)]["imagename"] + ".residual" |
675 + | tempresname = ( |
676 + | self.allimpars[str(immod)]["imagename"] |
677 + | + ".inputres" |
678 + | + str(self.ncycle) |
679 + | ) |
600 680 | if os.path.isdir(resname): |
601 681 | shutil.copytree(resname, tempresname) |
602 - | modname = self.allimpars[str(immod)]['imagename']+'.model' |
603 - | tempmodname = self.allimpars[str(immod)]['imagename']+'.inputmod'+str(self.ncycle) |
682 + | modname = self.allimpars[str(immod)]["imagename"] + ".model" |
683 + | tempmodname = ( |
684 + | self.allimpars[str(immod)]["imagename"] |
685 + | + ".inputmod" |
686 + | + str(self.ncycle) |
687 + | ) |
604 688 | if os.path.isdir(modname): |
605 689 | shutil.copytree(modname, tempmodname) |
606 690 | |
607 - | exrec = self.SDtools[immod].executeminorcycle( iterbotrecord = iterbotrec ) |
691 + | exrec = self.SDtools[immod].executeminorcycle(iterbotrecord=iterbotrec) |
608 692 | |
609 693 | # casalog.post('.... iterdone for ', immod, ' : ' , exrec['iterdone']) |
610 - | retval= retval or exrec['iterdone'] > 0 |
611 - | self.IBtool.mergeexecrecord( exrec, immod ) |
612 - | if alwaysSaveIntermediateImages or ('SAVE_ALL_AUTOMASKS' in os.environ and os.environ['SAVE_ALL_AUTOMASKS']=="true"): |
613 - | maskname = self.allimpars[str(immod)]['imagename']+'.mask' |
614 - | tempmaskname = self.allimpars[str(immod)]['imagename']+'.autothresh'+str(self.ncycle) |
694 + | retval = retval or exrec["iterdone"] > 0 |
695 + | self.IBtool.mergeexecrecord(exrec, immod) |
696 + | if alwaysSaveIntermediateImages or ( |
697 + | "SAVE_ALL_AUTOMASKS" in os.environ |
698 + | and os.environ["SAVE_ALL_AUTOMASKS"] == "true" |
699 + | ): |
700 + | maskname = self.allimpars[str(immod)]["imagename"] + ".mask" |
701 + | tempmaskname = ( |
702 + | self.allimpars[str(immod)]["imagename"] |
703 + | + ".autothresh" |
704 + | + str(self.ncycle) |
705 + | ) |
615 706 | if os.path.isdir(maskname): |
616 707 | shutil.copytree(maskname, tempmaskname) |
617 - | |
708 + | |
618 709 | # Some what duplicated as above but keep a copy of the previous mask |
619 710 | # for interactive automask to revert to it if the current mask |
620 711 | # is not used (i.e. reached deconvolution stopping condition). |
621 712 | ## no longer needed as of CAS-9386 for cubes. |
622 - | #if self.iterpars['interactive'] and self.alldecpars[str(immod)]['usemask']=='auto-thresh': |
623 - | if (self.alldecpars[str(immod)]['usemask'].count('auto')>0) : |
624 - | maskname = self.allimpars[str(immod)]['imagename']+'.mask' |
625 - | prevmaskname=self.allimpars[str(immod)]['imagename']+'.prev.mask' |
713 + | # if self.iterpars['interactive'] and self.alldecpars[str(immod)]['usemask']=='auto-thresh': |
714 + | if self.alldecpars[str(immod)]["usemask"].count("auto") > 0: |
715 + | maskname = self.allimpars[str(immod)]["imagename"] + ".mask" |
716 + | prevmaskname = ( |
717 + | self.allimpars[str(immod)]["imagename"] + ".prev.mask" |
718 + | ) |
626 719 | if os.path.isdir(maskname): |
627 720 | if os.path.isdir(prevmaskname): |
628 721 | shutil.rmtree(prevmaskname) |
629 722 | shutil.copytree(maskname, prevmaskname) |
630 723 | return retval |
631 724 | |
632 - | ############################################# |
725 + | ############################################# |
633 726 | def runMajorMinorLoops(self): |
634 - | self.runMajorCycle(isCleanCycle=False) |
635 - | while ( not self.hasConverged() ): |
636 - | self.runMinorCycle() |
637 - | self.runMajorCycle() |
638 - | |
639 - | ############################################# |
727 + | self.runMajorCycle(isCleanCycle=False) |
728 + | while not self.hasConverged(): |
729 + | self.runMinorCycle() |
730 + | self.runMajorCycle() |
640 731 | |
641 - | def plotReport( self, summ={} ,fignum=1 ): |
732 + | ############################################# |
642 733 | |
643 - | if not ( 'summaryminor' in summ and 'summarymajor' in summ and 'threshold' in summ and summ['summaryminor'].shape[0]==6 ): |
644 - | casalog.post('Cannot make summary plot. Please check contents of the output dictionary from tclean.') |
734 + | def plotReport(self, summ={}, fignum=1): |
735 + | |
736 + | if not ( |
737 + | "summaryminor" in summ |
738 + | and "summarymajor" in summ |
739 + | and "threshold" in summ |
740 + | and summ["summaryminor"].shape[0] == 6 |
741 + | ): |
742 + | casalog.post( |
743 + | "Cannot make summary plot. Please check contents of the output dictionary from tclean." |
744 + | ) |
645 745 | return summ |
646 746 | |
647 747 | import pylab as pl |
648 748 | from numpy import max as amax |
649 749 | |
650 750 | # 0 : iteration number (within deconvolver, per cycle) |
651 751 | # 1 : peak residual |
652 752 | # 2 : model flux |
653 753 | # 3 : cyclethreshold |
654 754 | # 4 : deconvolver id |
655 755 | # 5 : subimage id (channel, stokes..) |
656 756 | |
657 757 | pl.ioff() |
658 758 | |
659 - | fig, ax = pl.subplots(nrows=1,ncols=1,num=fignum) |
660 - | pl.clf(); |
661 - | minarr = summ['summaryminor'] |
662 - | if minarr.size==0: |
759 + | fig, ax = pl.subplots(nrows=1, ncols=1, num=fignum) |
760 + | pl.clf() |
761 + | minarr = summ["summaryminor"] |
762 + | if minarr.size == 0: |
663 763 | casalog.post("Zero iteration: no summary plot is generated.", "WARN") |
664 764 | else: |
665 - | iterlist = minarr[0,:] |
666 - | eps=0.0 |
667 - | peakresstart=[] |
668 - | peakresend=[] |
669 - | modfluxstart=[] |
670 - | modfluxend=[] |
671 - | itercountstart=[] |
672 - | itercountend=[] |
673 - | peakresstart.append( minarr[1,:][0] ) |
674 - | modfluxstart.append( minarr[2,:][0] ) |
675 - | itercountstart.append( minarr[0,:][0] + eps ) |
676 - | peakresend.append( minarr[1,:][0] ) |
677 - | modfluxend.append( minarr[2,:][0] ) |
678 - | itercountend.append( minarr[0,:][0] + eps ) |
679 - | for ii in range(0,len(iterlist)-1): |
680 - | if iterlist[ii]==iterlist[ii+1]: |
681 - | peakresend.append( minarr[1,:][ii] ) |
682 - | peakresstart.append( minarr[1,:][ii+1] ) |
683 - | modfluxend.append( minarr[2,:][ii] ) |
684 - | modfluxstart.append( minarr[2,:][ii+1] ) |
685 - | itercountend.append( iterlist[ii]-eps ) |
686 - | itercountstart.append( iterlist[ii]+eps ) |
687 - | |
688 - | peakresend.append( minarr[1,:][len(iterlist)-1] ) |
689 - | modfluxend.append( minarr[2,:][len(iterlist)-1] ) |
690 - | itercountend.append( minarr[0,:][len(iterlist)-1] + eps ) |
691 - | |
692 - | # pl.plot( iterlist , minarr[1,:] , 'r.-' , label='peak residual' , linewidth=1.5, markersize=8.0) |
693 - | # pl.plot( iterlist , minarr[2,:] , 'b.-' , label='model flux' ) |
694 - | # pl.plot( iterlist , minarr[3,:] , 'g--' , label='cycle threshold' ) |
695 - | |
696 - | pl.plot( itercountstart , peakresstart , 'r.--' , label='peak residual (start)') |
697 - | pl.plot( itercountend , peakresend , 'r.-' , label='peak residual (end)',linewidth=2.5) |
698 - | pl.plot( itercountstart , modfluxstart , 'b.--' , label='model flux (start)' ) |
699 - | pl.plot( itercountend , modfluxend , 'b.-' , label='model flux (end)',linewidth=2.5 ) |
700 - | pl.plot( iterlist , minarr[3,:] , 'g--' , label='cycle threshold', linewidth=2.5 ) |
701 - | maxval = amax( minarr[1,:] ) |
702 - | maxval = max( maxval, amax( minarr[2,:] ) ) |
703 - | |
704 - | bcols = ['b','g','r','y','c'] |
705 - | minv=1 |
706 - | niterdone = len(minarr[4,:]) |
707 - | |
708 - | if len(summ['summarymajor'].shape)==1 and summ['summarymajor'].shape[0]>0 : |
709 - | pl.vlines(summ['summarymajor'],0,maxval, label='major cycles', linewidth=2.0) |
710 - | |
711 - | pl.hlines( summ['threshold'], 0, summ['iterdone'] , linestyle='dashed' ,label='threshold') |
712 - | |
713 - | pl.xlabel( 'Iteration Count' ) |
714 - | pl.ylabel( 'Peak Residual (red), Model Flux (blue)' ) |
765 + | iterlist = minarr[0, :] |
766 + | eps = 0.0 |
767 + | peakresstart = [] |
768 + | peakresend = [] |
769 + | modfluxstart = [] |
770 + | modfluxend = [] |
771 + | itercountstart = [] |
772 + | itercountend = [] |
773 + | peakresstart.append(minarr[1, :][0]) |
774 + | modfluxstart.append(minarr[2, :][0]) |
775 + | itercountstart.append(minarr[0, :][0] + eps) |
776 + | peakresend.append(minarr[1, :][0]) |
777 + | modfluxend.append(minarr[2, :][0]) |
778 + | itercountend.append(minarr[0, :][0] + eps) |
779 + | for ii in range(0, len(iterlist) - 1): |
780 + | if iterlist[ii] == iterlist[ii + 1]: |
781 + | peakresend.append(minarr[1, :][ii]) |
782 + | peakresstart.append(minarr[1, :][ii + 1]) |
783 + | modfluxend.append(minarr[2, :][ii]) |
784 + | modfluxstart.append(minarr[2, :][ii + 1]) |
785 + | itercountend.append(iterlist[ii] - eps) |
786 + | itercountstart.append(iterlist[ii] + eps) |
787 + | |
788 + | peakresend.append(minarr[1, :][len(iterlist) - 1]) |
789 + | modfluxend.append(minarr[2, :][len(iterlist) - 1]) |
790 + | itercountend.append(minarr[0, :][len(iterlist) - 1] + eps) |
791 + | |
792 + | # pl.plot( iterlist , minarr[1,:] , 'r.-' , label='peak residual' , linewidth=1.5, markersize=8.0) |
793 + | # pl.plot( iterlist , minarr[2,:] , 'b.-' , label='model flux' ) |
794 + | # pl.plot( iterlist , minarr[3,:] , 'g--' , label='cycle threshold' ) |
795 + | |
796 + | pl.plot(itercountstart, peakresstart, "r.--", label="peak residual (start)") |
797 + | pl.plot( |
798 + | itercountend, |
799 + | peakresend, |
800 + | "r.-", |
801 + | label="peak residual (end)", |
802 + | linewidth=2.5, |
803 + | ) |
804 + | pl.plot(itercountstart, modfluxstart, "b.--", label="model flux (start)") |
805 + | pl.plot( |
806 + | itercountend, modfluxend, "b.-", label="model flux (end)", linewidth=2.5 |
807 + | ) |
808 + | pl.plot( |
809 + | iterlist, minarr[3, :], "g--", label="cycle threshold", linewidth=2.5 |
810 + | ) |
811 + | maxval = amax(minarr[1, :]) |
812 + | maxval = max(maxval, amax(minarr[2, :])) |
813 + | |
814 + | bcols = ["b", "g", "r", "y", "c"] |
815 + | minv = 1 |
816 + | niterdone = len(minarr[4, :]) |
817 + | |
818 + | if ( |
819 + | len(summ["summarymajor"].shape) == 1 |
820 + | and summ["summarymajor"].shape[0] > 0 |
821 + | ): |
822 + | pl.vlines( |
823 + | summ["summarymajor"], 0, maxval, label="major cycles", linewidth=2.0 |
824 + | ) |
825 + | |
826 + | pl.hlines( |
827 + | summ["threshold"], |
828 + | 0, |
829 + | summ["iterdone"], |
830 + | linestyle="dashed", |
831 + | label="threshold", |
832 + | ) |
833 + | |
834 + | pl.xlabel("Iteration Count") |
835 + | pl.ylabel("Peak Residual (red), Model Flux (blue)") |
715 836 | |
716 837 | box = ax.get_position() |
717 - | ax.set_position([box.x0, box.y0, box.width, box.height*0.8]) |
838 + | ax.set_position([box.x0, box.y0, box.width, box.height * 0.8]) |
718 839 | |
719 - | pl.legend(loc='lower center', bbox_to_anchor=(0.5, 1.05), |
720 - | ncol=3, fancybox=True, shadow=True) |
840 + | pl.legend( |
841 + | loc="lower center", |
842 + | bbox_to_anchor=(0.5, 1.05), |
843 + | ncol=3, |
844 + | fancybox=True, |
845 + | shadow=True, |
846 + | ) |
721 847 | |
722 - | pl.savefig('summaryplot_'+str(fignum)+'.png') |
848 + | pl.savefig("summaryplot_" + str(fignum) + ".png") |
723 849 | pl.ion() |
724 850 | |
725 - | return summ; |
851 + | return summ |
852 + | |
726 853 | ############################################# |
727 854 | |
728 - | def unlockimages( self, imageid=0 ): |
855 + | def unlockimages(self, imageid=0): |
729 856 | """ |
730 - | Will try to unlock images attached for the image or outlier field id |
857 + | Will try to unlock images attached for the image or outlier field id |
731 858 | in this instance |
732 859 | """ |
733 - | retval=False; |
734 - | if(len(self.PStools)> imageid): |
735 - | retval=self.SItool.unlockimages(imageid) |
736 - | retval=retval and self.PStools[imageid].unlockimages() |
860 + | retval = False |
861 + | if len(self.PStools) > imageid: |
862 + | retval = self.SItool.unlockimages(imageid) |
863 + | retval = retval and self.PStools[imageid].unlockimages() |
737 864 | return retval |
865 + | |
866 + | |
738 867 | ####################################################### |
739 868 | ####################################################### |