1
2 """Common stuff for classes that use analyzers"""
3
4 from os import path,mkdir
5 from shutil import move,rmtree
6
7 from PyFoam.Basics.PlotTimelinesFactory import createPlotTimelines,createPlotTimelinesDirect
8 from PyFoam.Basics.TimeLineCollection import signedMax
9 from PyFoam.LogAnalysis.RegExpLineAnalyzer import RegExpLineAnalyzer
10 from PyFoam.LogAnalysis.PhaseChangerLineAnalyzer import PhaseChangerLineAnalyzer
11
12 from PyFoam.Error import error
13
14
15 from PyFoam.ThirdParty.six.moves import cPickle as pickle
16
17 from PyFoam.Basics.GeneralPlotTimelines import allPlots
18 from PyFoam.Basics.TimeLineCollection import allLines
19
20 from threading import Lock
21
23 """This class collects information and methods that are needed for
24 handling analyzers"""
25
26 - def __init__(self,
27 filename,
28 analyzer,
29 doPickling=True):
30 """@param filename: name of the file that is being analyzed
31 @param analyzer: the analyzer itself
32 @param doPickling: write the pickled plot data"""
33
34 self.analyzer=analyzer
35
36 if 'dir' in dir(self):
37 self.logDir=path.join(self.dir,filename+".analyzed")
38 else:
39 self.logDir=filename+".analyzed"
40
41 if path.exists(self.logDir):
42
43 rmtree(self.logDir,ignore_errors=True)
44 mkdir(self.logDir)
45
46 self.doPickling=doPickling
47 if self.doPickling:
48 self.pickleLock=Lock()
49
50 self.reset()
51
52 if hasattr(self,"data"):
53 pickleFile=path.join(self.logDir,"pickledStartData")
54 pick=pickle.Pickler(open(pickleFile,"wb"))
55 pick.dump(self.data)
56
58 self.analyzer.tearDown()
59 if hasattr(self,"data"):
60 pickleFile=path.join(self.logDir,"pickledData")
61 pick=pickle.Pickler(open(pickleFile,"wb"))
62 pick.dump(self.data)
63
65 """@returns: A list with the names of the analyzers"""
66 return self.analyzer.listAnalyzers()
67
69 """@param name: name of the LineAnalyzer to get"""
70 return self.analyzer.getAnalyzer(name)
71
73 """@param name: name of the LineAnalyzer we ask for"""
74 return self.analyzer.hasAnalyzer(name)
75
77 """@param name: name of the LineAnalyzer to add
78 @param analyzer: the analyzer to add"""
79 analyzer.setDirectory(self.logDir)
80 return self.analyzer.addAnalyzer(name,analyzer)
81
83 """Not to be called: calls the analyzer for the current line"""
84 self.analyzer.analyzeLine(line)
85
87 """reset the analyzer"""
88 self.analyzer.setDirectory(self.logDir)
89
91 """Get the name of the directory where the data is written to"""
92 return self.logDir
93
95 """Get the execution time"""
96 return self.analyzer.getTime()
97
98 - def addTrigger(self,time,func,once=True,until=None):
99 """Adds a timed trigger to the Analyzer
100 @param time: the time at which the function should be triggered
101 @param func: the trigger function
102 @param once: Should this function be called once or at every time-step
103 @param until: The time until which the trigger should be called"""
104
105 self.analyzer.addTrigger(time,func,once=once,until=until)
106
107 - def createPlots(self,
108 persist=None,
109 raiseit=False,
110 splitThres=2048,
111 plotLinear=True,
112 plotCont=True,
113 plotBound=True,
114 plotIterations=True,
115 plotCourant=True,
116 plotExecution=True,
117 plotDeltaT=True,
118 start=None,
119 end=None,
120 writeFiles=False,
121 customRegexp=None,
122 plottingImplementation="dummy"):
123
124 plots={}
125
126 if plotLinear and self.hasAnalyzer("Linear"):
127 plots["linear"]=createPlotTimelinesDirect("linear",
128 self.getAnalyzer("Linear").lines,
129 persist=persist,
130 raiseit=raiseit,
131 forbidden=["final","iterations"],
132 start=start,
133 end=end,
134 logscale=True,
135 implementation=plottingImplementation)
136 self.getAnalyzer("Linear").lines.setSplitting(splitThres=splitThres,
137 splitFun=max,
138 advancedSplit=True)
139
140 plots["linear"].setTitle("Residuals")
141 plots["linear"].setYLabel("Initial residual")
142
143 if plotCont and self.hasAnalyzer("Continuity"):
144 plots["cont"]=createPlotTimelinesDirect("continuity",
145 self.getAnalyzer("Continuity").lines,
146 persist=persist,
147 alternateAxis=["Global"],
148 raiseit=raiseit,
149 start=start,
150 end=end,
151 implementation=plottingImplementation)
152 plots["cont"].setYLabel("Cumulative")
153 plots["cont"].setYLabel2("Global")
154 self.getAnalyzer("Continuity").lines.setSplitting(splitThres=splitThres,
155 advancedSplit=True)
156
157 plots["cont"].setTitle("Continuity")
158
159 if plotBound and self.hasAnalyzer("Bounding"):
160 plots["bound"]=createPlotTimelinesDirect("bounding",
161 self.getAnalyzer("Bounding").lines,
162 persist=persist,
163 raiseit=raiseit,
164 start=start,
165 end=end,
166 implementation=plottingImplementation)
167 self.getAnalyzer("Bounding").lines.setSplitting(splitThres=splitThres,
168 splitFun=signedMax,
169 advancedSplit=True)
170 plots["bound"].setTitle("Bounded variables")
171
172 if plotIterations and self.hasAnalyzer("Iterations"):
173 plots["iter"]=createPlotTimelinesDirect("iterations",
174 self.getAnalyzer("Iterations").lines,
175 persist=persist,
176 with_="steps",
177 raiseit=raiseit,
178 start=start,
179 end=end,
180 implementation=plottingImplementation)
181 self.getAnalyzer("Iterations").lines.setSplitting(splitThres=splitThres,
182 advancedSplit=True)
183
184 plots["iter"].setTitle("Iterations")
185 plots["iter"].setYLabel("Sum of iterations")
186
187 if plotCourant and self.hasAnalyzer("Courant"):
188 plots["courant"]=createPlotTimelinesDirect("courant",
189 self.getAnalyzer("Courant").lines,
190 persist=persist,
191 raiseit=raiseit,
192 start=start,
193 end=end,
194 implementation=plottingImplementation)
195 self.getAnalyzer("Courant").lines.setSplitting(splitThres=splitThres,
196 advancedSplit=True)
197
198 plots["courant"].setTitle("Courant")
199 plots["courant"].setYLabel("Courant Number [1]")
200
201 if plotDeltaT and self.hasAnalyzer("DeltaT"):
202 plots["deltaT"]=createPlotTimelinesDirect("timestep",
203 self.getAnalyzer("DeltaT").lines,
204 persist=persist,
205 raiseit=raiseit,
206 start=start,
207 end=end,
208 logscale=True,
209 implementation=plottingImplementation)
210 self.getAnalyzer("DeltaT").lines.setSplitting(splitThres=splitThres,
211 advancedSplit=True)
212
213 plots["deltaT"].setTitle("DeltaT")
214 plots["deltaT"].setYLabel("dt [s]")
215
216 if plotExecution and self.hasAnalyzer("Execution"):
217 plots["execution"]=createPlotTimelinesDirect("execution",
218 self.getAnalyzer("Execution").lines,
219 persist=persist,
220 with_="steps",
221 raiseit=raiseit,
222 start=start,
223 end=end,
224 implementation=plottingImplementation)
225 self.getAnalyzer("Execution").lines.setSplitting(splitThres=splitThres,
226 advancedSplit=True)
227
228 plots["execution"].setTitle("Execution Time")
229 plots["execution"].setYLabel("Time [s]")
230
231 if customRegexp:
232 self.plotCustom=[]
233 masters={}
234 slaves=[]
235 for i,custom in enumerate(customRegexp):
236 if not custom.enabled:
237 continue
238
239 if persist!=None:
240 custom.persist=persist
241 if start!=None:
242 custom.start=start
243 if end!=None:
244 custom.end=end
245 custom.raiseit=raiseit
246
247 createPlot=True
248 if custom.type=="phase":
249 self.addAnalyzer(custom.name,
250 PhaseChangerLineAnalyzer(custom.expr,
251 idNr=custom.idNr))
252 createPlot=False
253 elif custom.type=="dynamic":
254 self.addAnalyzer(custom.name,
255 RegExpLineAnalyzer(custom.name.lower(),
256 custom.expr,
257 titles=custom.titles,
258 doTimelines=True,
259 doFiles=writeFiles,
260 accumulation=custom.accumulation,
261 progressTemplate=custom.progress,
262 singleFile=True,
263 idNr=custom.idNr,
264 startTime=custom.start,
265 endTime=custom.end))
266
267 elif custom.type=="regular" or custom.type=="slave":
268 self.addAnalyzer(custom.name,
269 RegExpLineAnalyzer(custom.name.lower(),
270 custom.expr,
271 titles=custom.titles,
272 doTimelines=True,
273 doFiles=writeFiles,
274 accumulation=custom.accumulation,
275 progressTemplate=custom.progress,
276 singleFile=True,
277 startTime=custom.start,
278 endTime=custom.end))
279 else:
280 error("Unknown type",custom.type,"in custom expression",custom.name)
281
282 if createPlot:
283 if custom.master==None:
284 if custom.type=="slave":
285 error("Custom expression",custom.name,"is supposed to be a 'slave' but no master is defined")
286 masters[custom.id]=custom
287 plotCustom=createPlotTimelines(self.getAnalyzer(custom.name).lines,
288 custom=custom,
289 implementation=plottingImplementation)
290 self.getAnalyzer(custom.name).lines.setSplitting(splitThres=splitThres,
291 advancedSplit=True)
292 plotCustom.setTitle(custom.theTitle)
293 plots["custom%04d" % i]=plotCustom
294 else:
295 if custom.type!="slave":
296 error("'master' only makes sense if type is 'slave' for",custom.name)
297 if getattr(custom,"alternateAxis",None):
298 error("Specify alternate values in 'alternateAxis' of master",
299 custom.master,"for",custom.name)
300 slaves.append(custom)
301
302 for s in slaves:
303 if s.master not in masters:
304 error("The custom plot",s.id,"wants the master plot",
305 s.master,"but it is not found in the list of masters",
306 list(masters.keys()))
307 else:
308 slave=self.getAnalyzer(s.name)
309 master=self.getAnalyzer(masters[s.master].name)
310 slave.setMaster(master)
311
312 self.reset()
313
314 return plots
315
317 """Writes the necessary information for the plots permanently to disc,
318 so that it doesn't have to be generated again
319 @param wait: wait for the lock to be allowed to pickle"""
320
321
322
323 lines=allLines()
324 plots=allPlots()
325 if lines and plots:
326 gotIt=self.pickleLock.acquire(wait)
327 if not gotIt:
328 return
329
330 pickleFile=path.join(self.logDir,"pickledPlots")
331 pick=pickle.Pickler(open(pickleFile+".tmp","wb"))
332 pick.dump(lines.prepareForTransfer())
333 pick.dump(plots.prepareForTransfer())
334 move(pickleFile+".tmp",pickleFile)
335
336 if hasattr(self,"data"):
337 pickleFile=path.join(self.logDir,"pickledUnfinishedData")
338 pick=pickle.Pickler(open(pickleFile+".tmp","wb"))
339 pick.dump(self.data)
340 del pick
341 move(pickleFile+".tmp",pickleFile)
342
343 self.pickleLock.release()
344
346 if hasattr(self,"data"):
347 self.data["analyzed"]=data
348
349
350