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 7945 2012-03-29T15:50:57.506443Z 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 22 functionObject and generates the commands to gnuplot it. As an option 23 the data can be written to a 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("--fields", 41 action="append", 42 default=None, 43 dest="fields", 44 help="The fields 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="fields", 122 choices=["fields","positions"], 123 help="Collect lines for lineplotting either by 'fields' 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 output.add_option("--silent", 187 action="store_true", 188 dest="silent", 189 default=False, 190 help="Don't write to screen (with the silent and the compare-options)")
191
192 - def setFile(self,fName):
193 if self.opts.namePrefix: 194 fName=self.opts.namePrefix+"_"+fName 195 if self.opts.pictureDest: 196 fName=path.join(self.opts.pictureDest,fName) 197 198 name=fName 199 if self.opts.cleanFilename: 200 name=cleanFilename(fName) 201 return 'set output "%s"\n' % name
202
203 - def run(self):
204 # remove trailing slashif present 205 if self.opts.dirName[-1]==path.sep: 206 self.opts.dirName=self.opts.dirName[:-1] 207 208 timelines=TimelineDirectory(self.parser.getArgs()[0], 209 dirName=self.opts.dirName, 210 writeTime=self.opts.writeTime) 211 reference=None 212 if self.opts.reference and self.opts.referenceCase: 213 self.error("Options --reference-directory and --reference-case are mutual exclusive") 214 if self.opts.csvFile and (self.opts.compare or self.opts.metrics): 215 self.error("Options --csv-file and --compare/--metrics are mutual exclusive") 216 217 if self.opts.reference: 218 reference=TimelineDirectory(self.parser.getArgs()[0], 219 dirName=self.opts.reference, 220 writeTime=self.opts.writeTime) 221 elif self.opts.referenceCase: 222 reference=TimelineDirectory(self.opts.referenceCase, 223 dirName=self.opts.dirName, 224 writeTime=self.opts.writeTime) 225 226 if self.opts.info: 227 self.setData({'writeTimes' : timelines.writeTimes, 228 'usedTimes' : timelines.usedTime, 229 'fields' : timelines.values, 230 'positions' : timelines.positions(), 231 'timeRange' : timelines.timeRange()}) 232 233 if not self.opts.silent: 234 print "Write Times : ",timelines.writeTimes 235 print "Used Time : ",timelines.usedTime 236 print "Fields : ",timelines.values, 237 if len(timelines.vectors)>0: 238 if not self.opts.silent: 239 print " Vectors: ",timelines.vectors 240 self.setData({'vectors':timelines.vectors}) 241 else: 242 if not self.opts.silent: 243 print 244 if not self.opts.silent: 245 print "Positions : ",timelines.positions() 246 print "Time range : ",timelines.timeRange() 247 248 if reference: 249 refData={'writeTimes' : reference.writeTimes, 250 'fields' : reference.values, 251 'positions' : reference.positions(), 252 'timeRange' : reference.timeRange()} 253 254 if not self.opts.silent: 255 print "\nReference Data" 256 print "Write Times : ",reference.writeTimes 257 print "Fields : ",reference.values, 258 if len(reference.vectors)>0: 259 if not self.opts.silent: 260 print " Vectors: ",reference.vectors 261 refData["vectors"]=reference.vectors 262 else: 263 if not self.opts.silent: 264 print 265 if not self.opts.silent: 266 print "Positions : ",reference.positions() 267 print "Time range : ",reference.timeRange() 268 self.setData({"reference":refData}) 269 270 return 0 271 272 if self.opts.fields==None: 273 self.opts.fields=timelines.values 274 else: 275 for v in self.opts.fields: 276 if v not in timelines.values: 277 self.error("The requested value",v,"not in possible values",timelines.values) 278 if self.opts.positions==None: 279 self.opts.positions=timelines.positions() 280 else: 281 pos=self.opts.positions 282 self.opts.positions=[] 283 for p in pos: 284 try: 285 p=int(p) 286 if p<0 or p>=len(timelines.positions()): 287 self.error("Time index",p,"out of range for positons",timelines.positions()) 288 else: 289 self.opts.positions.append(timelines.positions()[p]) 290 except ValueError: 291 if p not in timelines.positions(): 292 self.error("Position",p,"not in",timelines.positions()) 293 else: 294 self.opts.positions.append(p) 295 296 result="set term png nocrop enhanced \n" 297 298 if self.opts.basicMode==None: 299 self.error("No mode selected. Do so with '--basic-mode'") 300 elif self.opts.basicMode=='bars': 301 if self.opts.time==None: 302 self.error("No times specified for bar-plots") 303 self.opts.time.sort() 304 if self.opts.referenceTime and reference!=None: 305 minTime,maxTime=reference.timeRange() 306 else: 307 minTime,maxTime=timelines.timeRange() 308 usedTimes=[] 309 hasMin=False 310 for t in self.opts.time: 311 if t<minTime: 312 if not hasMin: 313 usedTimes.append(minTime) 314 hasMin=True 315 elif t>maxTime: 316 usedTimes.append(maxTime) 317 break 318 else: 319 usedTimes.append(t) 320 data=timelines.getData(usedTimes, 321 value=self.opts.fields, 322 position=self.opts.positions) 323 # print data 324 result+="set style data histogram\n" 325 result+="set style histogram cluster gap 1\n" 326 result+="set style fill solid border -1\n" 327 result+="set boxwidth 0.9\n" 328 result+="set xtics border in scale 1,0.5 nomirror rotate by 90 offset character 0, 0, 0\n" 329 # set xtic rotate by -45\n" 330 result+="set xtics (" 331 for i,p in enumerate(self.opts.positions): 332 if i>0: 333 result+=" , " 334 result+='"%s" %d' % (p,i) 335 result+=")\n" 336 for tm in usedTimes: 337 if abs(float(tm))>1e20: 338 continue 339 result+=self.setFile("%s_writeTime_%s_Time_%s.png" % (self.opts.dirName,timelines.usedTime,tm)) 340 result+='set title "Directory: %s WriteTime: %s Time: %s"\n' % (self.opts.dirName.replace("_","\\\\_"),timelines.usedTime,tm) 341 result+= "plot " 342 first=True 343 for val in self.opts.fields: 344 if first: 345 first=False 346 else: 347 result+=", " 348 result+='"-" title "%s" ' % val.replace("_","\\\\_") 349 result+="\n" 350 for v,t,vals in data: 351 if t==tm: 352 for v in vals: 353 result+="%g\n" % v 354 result+="e\n" 355 elif self.opts.basicMode=='lines': 356 # print self.opts.positions 357 oPlots=timelines.getDataLocation(value=self.opts.fields, 358 position=self.opts.positions, 359 vectorMode=self.opts.vectorMode) 360 361 plots=oPlots[:] 362 rPlots=None 363 364 if reference: 365 rPlots=reference.getDataLocation(value=self.opts.fields, 366 position=self.opts.positions, 367 vectorMode=self.opts.vectorMode) 368 for gp,pos,val,comp,tv in rPlots: 369 plots.append((gp, 370 pos, 371 self.opts.refprefix+" "+val, 372 comp, 373 tv)) 374 if self.opts.referenceTime and reference!=None: 375 minTime,maxTime=reference.timeRange() 376 else: 377 minTime,maxTime=timelines.timeRange() 378 if self.opts.minTime: 379 minTime=self.opts.minTime 380 if self.opts.maxTime: 381 maxTime=self.opts.maxTime 382 result+= "set xrange [%g:%g]\n" % (minTime,maxTime) 383 if self.opts.collectLines=="fields": 384 for val in self.opts.fields: 385 vname=val 386 if val in timelines.vectors: 387 vname+="_"+self.opts.vectorMode 388 result+=self.setFile("%s_writeTime_%s_Value_%s.png" % (self.opts.dirName,timelines.usedTime,vname)) 389 result+='set title "Directory: %s WriteTime: %s Value: %s"\n' % (self.opts.dirName.replace("_","\\\\_"),timelines.usedTime,vname.replace("_","\\\\\\_")) 390 result+= "plot " 391 first=True 392 for f,v,p,i,tl in plots: 393 if v==val: 394 if first: 395 first=False 396 else: 397 result+=" , " 398 if type(i)==int: 399 result+= ' "%s" using 1:%d title "%s" with lines ' % (f,i+2,p.replace("_","\\\\_")) 400 else: 401 result+= ' "%s" using 1:%s title "%s" with lines ' % (f,i,p.replace("_","\\\\_")) 402 403 result+="\n" 404 elif self.opts.collectLines=="positions": 405 for pos in self.opts.positions: 406 result+=self.setFile("%s_writeTime_%s_Position_%s.png" % (self.opts.dirName,timelines.usedTime,pos)) 407 result+='set title "Directory: %s WriteTime: %s Position: %s"\n' % (self.opts.dirName.replace("_","\\\\_"),timelines.usedTime,pos.replace("_","\\\\_")) 408 result+= "plot " 409 first=True 410 for f,v,p,i in plots: 411 if p==pos: 412 if first: 413 first=False 414 else: 415 result+=" , " 416 if type(i)==int: 417 result+= ' "%s" using 1:%d title "%s" with lines ' % (f,i+2,v.replace("_","\\\\_")) 418 else: 419 result+= ' "%s" using 1:%s title "%s" with lines ' % (f,i,v.replace("_","\\\\_")) 420 result+="\n" 421 422 else: 423 self.error("Unimplemented collection of lines:",self.opts.collectLines) 424 else: 425 self.error("Not implemented basicMode",self.opts.basicMode) 426 427 if self.opts.csvFile: 428 if self.opts.basicMode!='lines': 429 self.error("CSV-files currently only supported for lines-mode") 430 spread=plots[0][-1]() 431 for line in plots[1:]: 432 if line[3]==0: 433 sp=line[-1]() 434 try: 435 spread+=sp 436 except WrongDataSize,e: 437 if self.opts.resample: 438 for n in sp.names()[1:]: 439 data=spread.resample(sp, 440 n, 441 extendData=self.opts.extendData) 442 try: 443 spread.append(n,data) 444 except ValueError: 445 spread.append(self.opts.refprefix+" "+n,data) 446 else: 447 self.warning("Try the --resample-option") 448 raise 449 450 spread.writeCSV(self.opts.csvFile) 451 elif self.opts.compare or self.opts.metrics: 452 statData={} 453 if self.opts.compare: 454 statData["compare"]={} 455 if self.opts.metrics: 456 statData["metrics"]={} 457 for p in self.opts.positions: 458 if self.opts.compare: 459 statData["compare"][p]={} 460 if self.opts.metrics: 461 statData["metrics"][p]={} 462 463 if self.opts.basicMode!='lines': 464 self.error("Compare currently only supported for lines-mode") 465 466 if self.opts.compare: 467 if rPlots==None: 468 self.error("No reference data specified. Can't compare") 469 elif len(rPlots)!=len(oPlots): 470 self.error("Number of original data sets",len(oPlots), 471 "is not equal to the reference data sets", 472 len(rPlots)) 473 474 for i,p in enumerate(oPlots): 475 pth,val,loc,ind,tl=p 476 if self.opts.compare: 477 rpth,rval,rloc,rind,rtl=rPlots[i] 478 if val!=rval or loc!=rloc or ind!=rind: 479 self.error("Original data",p,"and reference",rPlots[i], 480 "do not match") 481 data=tl() 482 try: 483 dataIndex=1+ind 484 if self.opts.metrics: 485 if not self.opts.silent: 486 print "Metrics for",val,"on",loc,"index",ind,"(Path:",pth,")" 487 result=data.metrics(data.names()[dataIndex]) 488 statData["metrics"][loc][val]=result 489 if not self.opts.silent: 490 print " Min :",result["min"] 491 print " Max :",result["max"] 492 print " Average :",result["average"] 493 print " Weighted average :",result["wAverage"] 494 if not self.opts.compare: 495 print "Data size:",data.size() 496 print " Time Range :",result["tMin"],result["tMax"] 497 if self.opts.compare: 498 if not self.opts.silent: 499 print "Comparing",val,"on",loc,"index",ind,"(path:",pth,")" 500 ref=rtl() 501 result=data.compare(ref,data.names()[dataIndex]) 502 statData["compare"][loc][val]=result 503 if not self.opts.silent: 504 print " Max difference :",result["max"] 505 print " Average difference :",result["average"] 506 print " Weighted average :",result["wAverage"] 507 print "Data size:",data.size(),"Reference:",ref.size() 508 if not self.opts.metrics: 509 print " Time Range :",result["tMin"],result["tMax"] 510 if not self.opts.silent: 511 print 512 except TypeError: 513 if self.opts.vectorMode=="mag": 514 self.error("Vector-mode 'mag' not supported for --compare and --metrics") 515 else: 516 raise 517 518 self.setData(statData) 519 else: 520 dest=sys.stdout 521 if self.opts.gnuplotFile: 522 dest=open(self.opts.gnuplotFile,"w") 523 524 dest.write(result)
525