1
2 """
3 Application class that implements pyFoamSamplePlot.py
4 """
5
6 import sys,string
7 from os import path
8 from optparse import OptionGroup
9
10 from PyFoamApplication import PyFoamApplication
11 from PyFoam.RunDictionary.SampleDirectory import SampleDirectory
12
13 from PyFoam.Error import error,warning
14
15 from PlotHelpers import cleanFilename
16
31
32 modeChoices=["separate","timesInOne","fieldsInOne","complete"]
33
35 data=OptionGroup(self.parser,
36 "Data",
37 "Select the data to plot")
38 self.parser.add_option_group(data)
39
40 data.add_option("--line",
41 action="append",
42 default=None,
43 dest="line",
44 help="Thesample line from which data is plotted (can be used more than once)")
45 data.add_option("--field",
46 action="append",
47 default=None,
48 dest="field",
49 help="The fields that are plotted (can be used more than once). If none are specified all found fields are used")
50 data.add_option("--directory-name",
51 action="store",
52 default="samples",
53 dest="dirName",
54 help="Alternate name for the directory with the samples (Default: %default)")
55 data.add_option("--preferred-component",
56 action="store",
57 type="int",
58 default=None,
59 dest="component",
60 help="The component that should be used for vectors. Otherwise the absolute value is used")
61
62 time=OptionGroup(self.parser,
63 "Time",
64 "Select the times to plot")
65 self.parser.add_option_group(time)
66
67 time.add_option("--time",
68 action="append",
69 default=None,
70 dest="time",
71 help="The times that are plotted (can be used more than once). If none are specified all found times are used")
72 time.add_option("--min-time",
73 action="store",
74 type="float",
75 default=None,
76 dest="minTime",
77 help="The smallest time that should be used")
78 time.add_option("--max-time",
79 action="store",
80 type="float",
81 default=None,
82 dest="maxTime",
83 help="The biggest time that should be used")
84 time.add_option("--fuzzy-time",
85 action="store_true",
86 default=False,
87 dest="fuzzyTime",
88 help="Try to find the next timestep if the time doesn't match exactly")
89
90 output=OptionGroup(self.parser,
91 "Appearance",
92 "How it should be plotted")
93 self.parser.add_option_group(output)
94
95 output.add_option("--mode",
96 type="choice",
97 default="separate",
98 dest="mode",
99 action="store",
100 choices=self.modeChoices,
101 help="What kind of plots are generated: a) separate for every time and field b) all times of a field in one plot c) all fields of a time in one plot d) all lines in one plot. (Names: "+string.join(self.modeChoices,", ")+") Default: %default")
102 output.add_option("--unscaled",
103 action="store_false",
104 dest="scaled",
105 default=True,
106 help="Don't scale a value to the same range for all plots")
107 output.add_option("--scale-all",
108 action="store_true",
109 dest="scaleAll",
110 default=False,
111 help="Use the same scale for all fields (else use one scale for each field)")
112 output.add_option("--gnuplot-file",
113 action="store",
114 dest="gnuplotFile",
115 default=None,
116 help="Write the necessary gnuplot commands to this file. Else they are written to the standard output")
117 output.add_option("--picture-destination",
118 action="store",
119 dest="pictureDest",
120 default=None,
121 help="Directory the pictures should be stored to")
122 output.add_option("--name-prefix",
123 action="store",
124 dest="namePrefix",
125 default=None,
126 help="Prefix to the picture-name")
127
128 data.add_option("--info",
129 action="store_true",
130 dest="info",
131 default=False,
132 help="Print info about the sampled data and exit")
133 output.add_option("--style",
134 action="store",
135 default="lines",
136 dest="style",
137 help="Gnuplot-style for the data (Default: %default)")
138 output.add_option("--clean-filename",
139 action="store_true",
140 dest="cleanFilename",
141 default=False,
142 help="Clean filenames so that they can be used in HTML or Latex-documents")
143
145 samples=SampleDirectory(self.parser.getArgs()[0],dirName=self.opts.dirName)
146
147 lines=samples.lines()
148 times=samples.times
149 values=samples.values()
150
151 if self.opts.info:
152 print "Times : ",samples.times
153 print "Lines : ",samples.lines()
154 print "Values: ",samples.values()
155 sys.exit(0)
156
157 if self.opts.line==None:
158
159 self.opts.line=lines
160 else:
161 for l in self.opts.line:
162 if l not in lines:
163 error("The line",l,"does not exist in",lines)
164
165 if self.opts.maxTime or self.opts.minTime:
166 if self.opts.time:
167 error("Times",self.opts.time,"and range [",self.opts.minTime,",",self.opts.maxTime,"] set: contradiction")
168 self.opts.time=[]
169 if self.opts.maxTime==None:
170 self.opts.maxTime= 1e20
171 if self.opts.minTime==None:
172 self.opts.minTime=-1e20
173
174 for t in times:
175 if float(t)<=self.opts.maxTime and float(t)>=self.opts.minTime:
176 self.opts.time.append(t)
177
178 if len(self.opts.time)==0:
179 error("No times in range [",self.opts.minTime,",",self.opts.maxTime,"] found: ",times)
180 elif self.opts.time:
181 iTimes=self.opts.time
182 self.opts.time=[]
183 for t in iTimes:
184 if t in samples.times:
185 self.opts.time.append(t)
186 elif self.opts.fuzzyTime:
187 tf=float(t)
188 use=None
189 dist=1e20
190 for ts in samples.times:
191 if abs(tf-float(ts))<dist:
192 use=ts
193 dist=abs(tf-float(ts))
194 if use and use not in self.opts.time:
195 self.opts.time.append(use)
196 else:
197 pass
198
199
200 plots=[]
201
202 if self.opts.mode=="separate":
203 if self.opts.time==None:
204 self.opts.time=samples.times
205 if self.opts.field==None:
206 self.opts.field=samples.values()
207 for t in self.opts.time:
208 for f in self.opts.field:
209 plots.append(samples.getData(line=self.opts.line,
210 value=[f],
211 time=[t]))
212 elif self.opts.mode=="timesInOne":
213 if self.opts.field==None:
214 self.opts.field=samples.values()
215 for f in self.opts.field:
216 plots.append(samples.getData(line=self.opts.line,
217 value=[f],
218 time=self.opts.time))
219 elif self.opts.mode=="fieldsInOne":
220 if self.opts.scaled and not self.opts.scaleAll:
221 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value")
222 self.opts.scaleAll=True
223
224 if self.opts.time==None:
225 self.opts.time=samples.times
226 for t in self.opts.time:
227 plots.append(samples.getData(line=self.opts.line,
228 value=self.opts.field,
229 time=[t]))
230 elif self.opts.mode=="complete":
231 if self.opts.scaled and not self.opts.scaleAll:
232 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value")
233 self.opts.scaleAll=True
234
235 plots.append(samples.getData(line=self.opts.line,
236 value=self.opts.field,
237 time=self.opts.time))
238
239 if self.opts.scaled:
240 if self.opts.scaleAll:
241 vRange=None
242 else:
243 vRanges={}
244
245 for p in plots:
246 for d in p:
247 mi,ma=d.range(component=self.opts.component)
248 nm=d.name
249 if not self.opts.scaleAll:
250 if nm in vRanges:
251 vRange=vRanges[nm]
252 else:
253 vRange=None
254
255 if vRange==None:
256 vRange=mi,ma
257 else:
258 vRange=min(vRange[0],mi),max(vRange[1],ma)
259 if not self.opts.scaleAll:
260 vRanges[nm]=vRange
261
262 result="set term png\n"
263
264 for p in plots:
265 if len(p)<1:
266 continue
267
268 name=""
269 if self.opts.namePrefix:
270 name+=self.opts.namePrefix+"_"
271 name+=self.opts.dirName
272 title=None
273 tIndex=times.index(p[0].time())
274
275 name+="_"+string.join(self.opts.line,"_")
276
277 if self.opts.mode=="separate":
278 name+="_%s_%04d" % (p[0].name,tIndex)
279 title="%s at t=%f" % (p[0].name,float(p[0].time()))
280 elif self.opts.mode=="timesInOne":
281 if self.opts.time!=None:
282 name+="_"+string.join(self.opts.time,"_")
283 name+="_%s" % p[0].name
284 title="%s" % p[0].name
285 elif self.opts.mode=="fieldsInOne":
286 if self.opts.field!=None:
287 name+="_"+string.join(self.opts.field,"_")
288 name+="_%04d" % tIndex
289 title="t=%f" % float(p[0].time())
290 elif self.opts.mode=="complete":
291 pass
292
293 name+=".png"
294 if self.opts.pictureDest:
295 name=path.join(self.opts.pictureDest,name)
296
297 if self.opts.cleanFilename:
298 name=cleanFilename(name)
299
300 result+='set output "%s"\n' % name
301 if title!=None:
302 result+='set title "%s"\n' % title
303
304 result+="plot "
305 if self.opts.scaled:
306 if not self.opts.scaleAll:
307 vRange=vRanges[p[0].name]
308
309
310 if abs(vRange[0]-vRange[1])>1e-5*max(abs(vRange[0]),abs(vRange[1])) and max(abs(vRange[0]),abs(vRange[1]))>1e-10:
311 result+="[][%g:%g] " % vRange
312
313 first=True
314
315 for d in p:
316 if first:
317 first=False
318 else:
319 result+=", "
320
321 colSpec="%s" % (d.index+1)
322 if d.isVector():
323 if self.opts.component:
324 colSpec="%d" % (d.index+1+self.opts.component)
325 else:
326 colSpec="(sqrt($%d**2+$%d**2+$%d**2))" % (d.index+1,d.index+2,d.index+3)
327
328 result+='"%s" using 1:%s ' % (d.file,colSpec)
329
330 title=None
331 if self.opts.mode=="separate":
332 title=""
333 elif self.opts.mode=="timesInOne":
334 title="t=%f" % float(d.time())
335 elif self.opts.mode=="fieldsInOne":
336 title="%s" % d.name
337 elif self.opts.mode=="complete":
338 title="%s at t=%f" % (d.name,float(d.time()))
339
340 if len(self.opts.line)>1:
341 title+=" on %s" % d.line()
342
343 if title=="":
344 result+="notitle "
345 else:
346 result+='title "%s" ' % title
347
348 result+="with %s " % self.opts.style
349
350 result+="\n"
351
352 dest=sys.stdout
353 if self.opts.gnuplotFile:
354 dest=open(self.opts.gnuplotFile,"w")
355
356 dest.write(result)
357