Package PyFoam :: Package Applications :: Module TimelinePlot
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.TimelinePlot

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/TimelinePlot.py 7393 2011-03-29T14:55:03.425417Z bgschaid  $  
  2  """ 
  3  Application class that implements pyFoamTimelinePlot.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.TimelineDirectory import TimelineDirectory 
 12  from PyFoam.Basics.SpreadsheetData import WrongDataSize 
 13   
 14  from PyFoam.Error import error,warning 
 15   
 16  from PlotHelpers import cleanFilename 
 17   
18 -class TimelinePlot(PyFoamApplication):
19 - def __init__(self,args=None):
20 description=""" 21 Searches a directory for timelines that were generated by some functionObject 22 and generates the commands to gnuplot it. As an option the data can be written to a 23 CSV-file. 24 """ 25 26 PyFoamApplication.__init__(self, 27 args=args, 28 description=description, 29 usage="%prog [options] <casedir>", 30 nr=1, 31 changeVersion=False, 32 interspersed=True)
33
34 - def addOptions(self):
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("--values", 41 action="append", 42 default=None, 43 dest="values", 44 help="The values for which timelines should be plotted. All if unset") 45 data.add_option("--positions", 46 action="append", 47 default=None, 48 dest="positions", 49 help="The positions for which timelines should be plotted. Either strings or integers (then the corresponding column number will be used). All if unset") 50 data.add_option("--write-time", 51 default=None, 52 dest="writeTime", 53 help="If more than one time-subdirectory is stored select which one is used") 54 data.add_option("--directory-name", 55 action="store", 56 default="probes", 57 dest="dirName", 58 help="Alternate name for the directory with the samples (Default: %default)") 59 data.add_option("--reference-directory", 60 action="store", 61 default=None, 62 dest="reference", 63 help="A reference directory. If fitting timeline data is found there it is plotted alongside the regular data") 64 data.add_option("--reference-case", 65 action="store", 66 default=None, 67 dest="referenceCase", 68 help="A reference case where a directory with the same name is looked for. Mutual exclusive with --reference-directory") 69 70 time=OptionGroup(self.parser, 71 "Time", 72 "Select the times to plot") 73 self.parser.add_option_group(time) 74 75 time.add_option("--time", 76 action="append", 77 type="float", 78 default=None, 79 dest="time", 80 help="The times that are plotted (can be used more than once). Has to be specified for bars") 81 time.add_option("--min-time", 82 action="store", 83 type="float", 84 default=None, 85 dest="minTime", 86 help="The smallest time that should be used for lines") 87 time.add_option("--max-time", 88 action="store", 89 type="float", 90 default=None, 91 dest="maxTime", 92 help="The biggest time that should be used for lines") 93 time.add_option("--reference-time", 94 action="store_true", 95 default=False, 96 dest="referenceTime", 97 help="Use the time of the reference data for scaling instead of the regular data") 98 99 100 plot=OptionGroup(self.parser, 101 "Plot", 102 "How data should be plotted") 103 self.parser.add_option_group(plot) 104 105 plot.add_option("--basic-mode", 106 type="choice", 107 dest="basicMode", 108 default=None, 109 choices=["bars","lines"], 110 help="Whether 'bars' of the values at selected times or 'lines' over the whole timelines should be plotted") 111 vModes=["mag","x","y","z"] 112 plot.add_option("--vector-mode", 113 type="choice", 114 dest="vectorMode", 115 default="mag", 116 choices=vModes, 117 help="How vectors should be plotted. By magnitude or as a component. Possible values are "+str(vModes)+" Default: %default") 118 plot.add_option("--collect-lines-by", 119 type="choice", 120 dest="collectLines", 121 default="values", 122 choices=["values","positions"], 123 help="Collect lines for lineplotting either by 'values' or 'positions'. Default: %default") 124 125 output=OptionGroup(self.parser, 126 "Output", 127 "Where data should be plotted to") 128 self.parser.add_option_group(output) 129 130 output.add_option("--gnuplot-file", 131 action="store", 132 dest="gnuplotFile", 133 default=None, 134 help="Write the necessary gnuplot commands to this file. Else they are written to the standard output") 135 output.add_option("--picture-destination", 136 action="store", 137 dest="pictureDest", 138 default=None, 139 help="Directory the pictures should be stored to") 140 output.add_option("--name-prefix", 141 action="store", 142 dest="namePrefix", 143 default=None, 144 help="Prefix to the picture-name") 145 output.add_option("--clean-filename", 146 action="store_true", 147 dest="cleanFilename", 148 default=False, 149 help="Clean filenames so that they can be used in HTML or Latex-documents") 150 output.add_option("--csv-file", 151 action="store", 152 dest="csvFile", 153 default=None, 154 help="Write the data to a CSV-file instead of the gnuplot-commands") 155 output.add_option("--reference-prefix", 156 action="store", 157 dest="refprefix", 158 default="Reference", 159 help="Prefix that gets added to the reference lines. Default: %default") 160 161 data.add_option("--info", 162 action="store_true", 163 dest="info", 164 default=False, 165 help="Print info about the sampled data and exit") 166 output.add_option("--resample", 167 action="store_true", 168 dest="resample", 169 default=False, 170 help="Resample the reference value to the current x-axis (for CSV-output)") 171 output.add_option("--extend-data", 172 action="store_true", 173 dest="extendData", 174 default=False, 175 help="Extend the data range if it differs (for CSV-files)") 176 output.add_option("--compare", 177 action="store_true", 178 dest="compare", 179 default=None, 180 help="Compare all data sets that are also in the reference data") 181 output.add_option("--metrics", 182 action="store_true", 183 dest="metrics", 184 default=None, 185 help="Print the metrics of the data sets")
186
187 - def setFile(self,fName):
188 if self.opts.namePrefix: 189 fName=self.opts.namePrefix+"_"+fName 190 if self.opts.pictureDest: 191 fName=path.join(self.opts.pictureDest,fName) 192 193 name=fName 194 if self.opts.cleanFilename: 195 name=cleanFilename(fName) 196 return 'set output "%s"\n' % name
197
198 - def run(self):
199 # remove trailing slashif present 200 if self.opts.dirName[-1]==path.sep: 201 self.opts.dirName=self.opts.dirName[:-1] 202 203 timelines=TimelineDirectory(self.parser.getArgs()[0], 204 dirName=self.opts.dirName, 205 writeTime=self.opts.writeTime) 206 reference=None 207 if self.opts.reference and self.opts.referenceCase: 208 self.error("Options --reference-directory and --reference-case are mutual exclusive") 209 if self.opts.csvFile and (self.opts.compare or self.opts.metrics): 210 self.error("Options --csv-file and --compare/--metrics are mutual exclusive") 211 212 if self.opts.reference: 213 reference=TimelineDirectory(self.parser.getArgs()[0], 214 dirName=self.opts.reference, 215 writeTime=self.opts.writeTime) 216 elif self.opts.referenceCase: 217 reference=TimelineDirectory(self.opts.referenceCase, 218 dirName=self.opts.dirName, 219 writeTime=self.opts.writeTime) 220 221 if self.opts.info: 222 print "Write Times : ",timelines.writeTimes 223 print "Used Time : ",timelines.usedTime 224 print "Values : ",timelines.values, 225 if len(timelines.vectors)>0: 226 print " Vectors: ",timelines.vectors 227 else: 228 print 229 print "Positions : ",timelines.positions() 230 print "Time range : ",timelines.timeRange() 231 232 if reference: 233 print "\nReference Data" 234 print "Write Times : ",reference.writeTimes 235 print "Fields : ",reference.values, 236 if len(reference.vectors)>0: 237 print " Vectors: ",reference.vectors 238 else: 239 print 240 print "Positions : ",reference.positions() 241 print "Time range : ",reference.timeRange() 242 243 return 0 244 245 if self.opts.values==None: 246 self.opts.values=timelines.values 247 else: 248 for v in self.opts.values: 249 if v not in timelines.values: 250 self.error("The requested value",v,"not in possible values",timelines.values) 251 if self.opts.positions==None: 252 self.opts.positions=timelines.positions() 253 else: 254 pos=self.opts.positions 255 self.opts.positions=[] 256 for p in pos: 257 try: 258 p=int(p) 259 if p<0 or p>=len(timelines.positions()): 260 self.error("Time index",p,"out of range for positons",timelines.positions()) 261 else: 262 self.opts.positions.append(timelines.positions()[p]) 263 except ValueError: 264 if p not in timelines.positions(): 265 self.error("Position",p,"not in",timelines.positions()) 266 else: 267 self.opts.positions.append(p) 268 269 result="set term png nocrop enhanced \n" 270 271 if self.opts.basicMode==None: 272 self.error("No mode selected. Do so with '--basic-mode'") 273 elif self.opts.basicMode=='bars': 274 if self.opts.time==None: 275 self.error("No times specified for bar-plots") 276 self.opts.time.sort() 277 if self.opts.referenceTime and reference!=None: 278 minTime,maxTime=reference.timeRange() 279 else: 280 minTime,maxTime=timelines.timeRange() 281 usedTimes=[] 282 hasMin=False 283 for t in self.opts.time: 284 if t<minTime: 285 if not hasMin: 286 usedTimes.append(minTime) 287 hasMin=True 288 elif t>maxTime: 289 usedTimes.append(maxTime) 290 break 291 else: 292 usedTimes.append(t) 293 data=timelines.getData(usedTimes, 294 value=self.opts.values, 295 position=self.opts.positions) 296 # print data 297 result+="set style data histogram\n" 298 result+="set style histogram cluster gap 1\n" 299 result+="set style fill solid border -1\n" 300 result+="set boxwidth 0.9\n" 301 result+="set xtics border in scale 1,0.5 nomirror rotate by 90 offset character 0, 0, 0\n" 302 # set xtic rotate by -45\n" 303 result+="set xtics (" 304 for i,p in enumerate(self.opts.positions): 305 if i>0: 306 result+=" , " 307 result+='"%s" %d' % (p,i) 308 result+=")\n" 309 for tm in usedTimes: 310 if abs(float(tm))>1e20: 311 continue 312 result+=self.setFile("%s_writeTime_%s_Time_%s.png" % (self.opts.dirName,timelines.usedTime,tm)) 313 result+='set title "Directory: %s WriteTime: %s Time: %s"\n' % (self.opts.dirName,timelines.usedTime,tm) 314 result+= "plot " 315 first=True 316 for val in self.opts.values: 317 if first: 318 first=False 319 else: 320 result+=", " 321 result+='"-" title "%s" ' % val 322 result+="\n" 323 for v,t,vals in data: 324 if t==tm: 325 for v in vals: 326 result+="%g\n" % v 327 result+="e\n" 328 elif self.opts.basicMode=='lines': 329 # print self.opts.positions 330 oPlots=timelines.getDataLocation(value=self.opts.values, 331 position=self.opts.positions, 332 vectorMode=self.opts.vectorMode) 333 334 plots=oPlots[:] 335 rPlots=None 336 337 if reference: 338 rPlots=reference.getDataLocation(value=self.opts.values, 339 position=self.opts.positions, 340 vectorMode=self.opts.vectorMode) 341 for gp,pos,val,comp,tv in rPlots: 342 plots.append((gp, 343 pos, 344 self.opts.refprefix+" "+val, 345 comp, 346 tv)) 347 if self.opts.referenceTime and reference!=None: 348 minTime,maxTime=reference.timeRange() 349 else: 350 minTime,maxTime=timelines.timeRange() 351 if self.opts.minTime: 352 minTime=self.opts.minTime 353 if self.opts.maxTime: 354 maxTime=self.opts.maxTime 355 result+= "set xrange [%g:%g]\n" % (minTime,maxTime) 356 if self.opts.collectLines=="values": 357 for val in self.opts.values: 358 vname=val 359 if val in timelines.vectors: 360 vname+="_"+self.opts.vectorMode 361 result+=self.setFile("%s_writeTime_%s_Value_%s.png" % (self.opts.dirName,timelines.usedTime,vname)) 362 result+='set title "Directory: %s WriteTime: %s Value: %s"\n' % (self.opts.dirName,timelines.usedTime,vname) 363 result+= "plot " 364 first=True 365 for f,v,p,i,tl in plots: 366 if v==val: 367 if first: 368 first=False 369 else: 370 result+=" , " 371 if type(i)==int: 372 result+= ' "%s" using 1:%d title "%s" with lines ' % (f,i+2,p) 373 else: 374 result+= ' "%s" using 1:%s title "%s" with lines ' % (f,i,p) 375 376 result+="\n" 377 elif self.opts.collectLines=="positions": 378 for pos in self.opts.positions: 379 result+=self.setFile("%s_writeTime_%s_Position_%s.png" % (self.opts.dirName,timelines.usedTime,pos)) 380 result+='set title "Directory: %s WriteTime: %s Position: %s"\n' % (self.opts.dirName,timelines.usedTime,pos) 381 result+= "plot " 382 first=True 383 for f,v,p,i in plots: 384 if p==pos: 385 if first: 386 first=False 387 else: 388 result+=" , " 389 if type(i)==int: 390 result+= ' "%s" using 1:%d title "%s" with lines ' % (f,i+2,v) 391 else: 392 result+= ' "%s" using 1:%s title "%s" with lines ' % (f,i,v) 393 result+="\n" 394 395 else: 396 self.error("Unimplemented collection of lines:",self.opts.collectLines) 397 else: 398 self.error("Not implemented basicMode",self.opts.basicMode) 399 400 if self.opts.csvFile: 401 if self.opts.basicMode!='lines': 402 self.error("CSV-files currently only supported for lines-mode") 403 spread=plots[0][-1]() 404 for line in plots[1:]: 405 if line[3]==0: 406 sp=line[-1]() 407 try: 408 spread+=sp 409 except WrongDataSize,e: 410 if self.opts.resample: 411 for n in sp.names()[1:]: 412 data=spread.resample(sp, 413 n, 414 extendData=self.opts.extendData) 415 try: 416 spread.append(n,data) 417 except ValueError: 418 spread.append(self.opts.refprefix+" "+n,data) 419 else: 420 self.warning("Try the --resample-option") 421 raise 422 423 spread.writeCSV(self.opts.csvFile) 424 elif self.opts.compare or self.opts.metrics: 425 if self.opts.basicMode!='lines': 426 self.error("Compare currently only supported for lines-mode") 427 428 if self.opts.compare: 429 if rPlots==None: 430 self.error("No reference data specified. Can't compare") 431 elif len(rPlots)!=len(oPlots): 432 self.error("Number of original data sets",len(oPlots), 433 "is not equal to the reference data sets", 434 len(rPlots)) 435 436 for i,p in enumerate(oPlots): 437 pth,val,loc,ind,tl=p 438 if self.opts.compare: 439 rpth,rval,rloc,rind,rtl=rPlots[i] 440 if val!=rval or loc!=rloc or ind!=rind: 441 self.error("Original data",p,"and reference",rPlots[i], 442 "do not match") 443 data=tl() 444 try: 445 dataIndex=1+ind 446 if self.opts.metrics: 447 print "Metrics for",val,"on",loc,"index",ind,"(Path:",pth,")" 448 result=data.metrics(data.names()[dataIndex]) 449 print " Min :",result["min"] 450 print " Max :",result["max"] 451 print " Average :",result["average"] 452 print " Weighted average :",result["wAverage"] 453 if not self.opts.compare: 454 print "Data size:",data.size() 455 print " Time Range :",result["tMin"],result["tMax"] 456 if self.opts.compare: 457 print "Comparing",val,"on",loc,"index",ind,"(path:",pth,")" 458 ref=rtl() 459 result=data.compare(ref,data.names()[dataIndex]) 460 print " Max difference :",result["max"] 461 print " Average difference :",result["average"] 462 print " Weighted average :",result["wAverage"] 463 print "Data size:",data.size(),"Reference:",ref.size() 464 if not self.opts.metrics: 465 print " Time Range :",result["tMin"],result["tMax"] 466 print 467 except TypeError: 468 if self.opts.vectorMode=="mag": 469 self.error("Vector-mode 'mag' not supported for --compare and --metrics") 470 else: 471 raise 472 else: 473 dest=sys.stdout 474 if self.opts.gnuplotFile: 475 dest=open(self.opts.gnuplotFile,"w") 476 477 dest.write(result)
478