Commits

Pam Harris authored 530e8194328 Merge
Merge branch 'master' into CAS-7164
No tags

casatasks/src/private/imagerhelpers/imager_base.py

Modified
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 #######################################################

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut