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

Source Code for Module PyFoam.Applications.SamplePlot

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/SamplePlot.py 7393 2011-03-29T14:55:03.425417Z bgschaid  $  
  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  from PyFoam.Basics.SpreadsheetData import WrongDataSize 
 13   
 14  from PyFoam.Error import error,warning 
 15   
 16  from PlotHelpers import cleanFilename 
 17   
18 -class SamplePlot(PyFoamApplication):
19 - def __init__(self,args=None):
20 description=""" 21 Reads data from the sample-dictionary and generates appropriate 22 gnuplot-commands. 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 modeChoices=["separate","timesInOne","fieldsInOne","linesInOne","complete"] 35
36 - def addOptions(self):
37 data=OptionGroup(self.parser, 38 "Data", 39 "Select the data to plot") 40 self.parser.add_option_group(data) 41 42 data.add_option("--line", 43 action="append", 44 default=None, 45 dest="line", 46 help="Thesample line from which data is plotted (can be used more than once)") 47 data.add_option("--field", 48 action="append", 49 default=None, 50 dest="field", 51 help="The fields that are plotted (can be used more than once). If none are specified all found fields are used") 52 data.add_option("--directory-name", 53 action="store", 54 default="samples", 55 dest="dirName", 56 help="Alternate name for the directory with the samples (Default: %default)") 57 data.add_option("--preferred-component", 58 action="store", 59 type="int", 60 default=None, 61 dest="component", 62 help="The component that should be used for vectors. Otherwise the absolute value is used") 63 data.add_option("--reference-directory", 64 action="store", 65 default=None, 66 dest="reference", 67 help="A reference directory. If fitting sample data is found there it is plotted alongside the regular data") 68 data.add_option("--reference-case", 69 action="store", 70 default=None, 71 dest="referenceCase", 72 help="A reference case where a directory with the same name is looked for. Mutual exclusive with --reference-directory") 73 74 time=OptionGroup(self.parser, 75 "Time", 76 "Select the times to plot") 77 self.parser.add_option_group(time) 78 79 time.add_option("--time", 80 action="append", 81 default=None, 82 dest="time", 83 help="The times that are plotted (can be used more than once). If none are specified all found times are used") 84 time.add_option("--min-time", 85 action="store", 86 type="float", 87 default=None, 88 dest="minTime", 89 help="The smallest time that should be used") 90 time.add_option("--max-time", 91 action="store", 92 type="float", 93 default=None, 94 dest="maxTime", 95 help="The biggest time that should be used") 96 time.add_option("--fuzzy-time", 97 action="store_true", 98 default=False, 99 dest="fuzzyTime", 100 help="Try to find the next timestep if the time doesn't match exactly") 101 102 output=OptionGroup(self.parser, 103 "Appearance", 104 "How it should be plotted") 105 self.parser.add_option_group(output) 106 107 output.add_option("--mode", 108 type="choice", 109 default="separate", 110 dest="mode", 111 action="store", 112 choices=self.modeChoices, 113 help="What kind of plots are generated: a) separate for every time, line 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 e) everything in one plot (Names: "+string.join(self.modeChoices,", ")+") Default: %default") 114 output.add_option("--unscaled", 115 action="store_false", 116 dest="scaled", 117 default=True, 118 help="Don't scale a value to the same range for all plots") 119 output.add_option("--scale-all", 120 action="store_true", 121 dest="scaleAll", 122 default=False, 123 help="Use the same scale for all fields (else use one scale for each field)") 124 output.add_option("--gnuplot-file", 125 action="store", 126 dest="gnuplotFile", 127 default=None, 128 help="Write the necessary gnuplot commands to this file. Else they are written to the standard output") 129 output.add_option("--picture-destination", 130 action="store", 131 dest="pictureDest", 132 default=None, 133 help="Directory the pictures should be stored to") 134 output.add_option("--name-prefix", 135 action="store", 136 dest="namePrefix", 137 default=None, 138 help="Prefix to the picture-name") 139 output.add_option("--csv-file", 140 action="store", 141 dest="csvFile", 142 default=None, 143 help="Write the data to a CSV-file instead of the gnuplot-commands") 144 145 data.add_option("--info", 146 action="store_true", 147 dest="info", 148 default=False, 149 help="Print info about the sampled data and exit") 150 output.add_option("--style", 151 action="store", 152 default="lines", 153 dest="style", 154 help="Gnuplot-style for the data (Default: %default)") 155 output.add_option("--clean-filename", 156 action="store_true", 157 dest="cleanFilename", 158 default=False, 159 help="Clean filenames so that they can be used in HTML or Latex-documents") 160 output.add_option("--reference-prefix", 161 action="store", 162 dest="refprefix", 163 default="Reference", 164 help="Prefix that gets added to the reference lines. Default: %default") 165 output.add_option("--resample-reference", 166 action="store_true", 167 dest="resampleReference", 168 default=False, 169 help="Resample the reference value to the current x-axis (for CSV-output)") 170 output.add_option("--extend-data", 171 action="store_true", 172 dest="extendData", 173 default=False, 174 help="Extend the data range if it differs (for CSV-files)") 175 output.add_option("--compare", 176 action="store_true", 177 dest="compare", 178 default=None, 179 help="Compare all data sets that are also in the reference data") 180 output.add_option("--metrics", 181 action="store_true", 182 dest="metrics", 183 default=None, 184 help="Print the metrics of the data sets")
185
186 - def run(self):
187 samples=SampleDirectory(self.parser.getArgs()[0], 188 dirName=self.opts.dirName) 189 reference=None 190 if self.opts.reference and self.opts.referenceCase: 191 self.error("Options --reference-directory and --reference-case are mutual exclusive") 192 if self.opts.csvFile and (self.opts.compare or self.opts.metrics): 193 self.error("Options --csv-file and --compare/--metrics are mutual exclusive") 194 195 if self.opts.reference: 196 reference=SampleDirectory(self.parser.getArgs()[0], 197 dirName=self.opts.reference) 198 elif self.opts.referenceCase: 199 reference=SampleDirectory(self.opts.referenceCase, 200 dirName=self.opts.dirName) 201 202 lines=samples.lines() 203 times=samples.times 204 values=samples.values() 205 206 if self.opts.info: 207 print "Times : ",samples.times 208 print "Lines : ",samples.lines() 209 print "Fields: ",samples.values() 210 211 if reference: 212 print "\nReference Data:" 213 print "Times : ",reference.times 214 print "Lines : ",reference.lines() 215 print "Fields: ",reference.values() 216 217 return 0 218 219 if self.opts.line==None: 220 # error("At least one line has to be specified. Found were",samples.lines()) 221 self.opts.line=lines 222 else: 223 for l in self.opts.line: 224 if l not in lines: 225 error("The line",l,"does not exist in",lines) 226 227 if self.opts.maxTime or self.opts.minTime: 228 if self.opts.time: 229 error("Times",self.opts.time,"and range [",self.opts.minTime,",",self.opts.maxTime,"] set: contradiction") 230 self.opts.time=[] 231 if self.opts.maxTime==None: 232 self.opts.maxTime= 1e20 233 if self.opts.minTime==None: 234 self.opts.minTime=-1e20 235 236 for t in times: 237 if float(t)<=self.opts.maxTime and float(t)>=self.opts.minTime: 238 self.opts.time.append(t) 239 240 if len(self.opts.time)==0: 241 error("No times in range [",self.opts.minTime,",",self.opts.maxTime,"] found: ",times) 242 elif self.opts.time: 243 iTimes=self.opts.time 244 self.opts.time=[] 245 for t in iTimes: 246 if t in samples.times: 247 self.opts.time.append(t) 248 elif self.opts.fuzzyTime: 249 tf=float(t) 250 use=None 251 dist=1e20 252 for ts in samples.times: 253 if abs(tf-float(ts))<dist: 254 use=ts 255 dist=abs(tf-float(ts)) 256 if use and use not in self.opts.time: 257 self.opts.time.append(use) 258 else: 259 pass 260 # self.warning("Time",t,"not found in the sample-times. Use option --fuzzy") 261 262 plots=[] 263 oPlots=[] 264 rPlots=[] 265 266 if self.opts.mode=="separate": 267 if self.opts.time==None: 268 self.opts.time=samples.times 269 if self.opts.field==None: 270 self.opts.field=samples.values() 271 if self.opts.line==None: 272 self.opts.line=samples.lines() 273 for t in self.opts.time: 274 for f in self.opts.field: 275 for l in self.opts.line: 276 plot=samples.getData(line=[l], 277 value=[f], 278 time=[t]) 279 oPlots.append(plot[:]) 280 if reference: 281 p=reference.getData(line=[l], 282 value=[f], 283 time=[t], 284 note=self.opts.refprefix+" ") 285 rPlots.append(p) 286 plot+=p 287 plots.append(plot) 288 289 elif self.opts.mode=="timesInOne": 290 if self.opts.field==None: 291 self.opts.field=samples.values() 292 if self.opts.line==None: 293 self.opts.line=samples.lines() 294 for f in self.opts.field: 295 for l in self.opts.line: 296 plot=samples.getData(line=[l], 297 value=[f], 298 time=self.opts.time) 299 oPlots.append(plot[:]) 300 301 if reference: 302 p=reference.getData(line=[l], 303 value=[f], 304 time=self.opts.time, 305 note=self.opts.refprefix+" ") 306 rPlots.append(p) 307 plot+=p 308 309 plots.append(plot) 310 311 elif self.opts.mode=="fieldsInOne": 312 if self.opts.scaled and not self.opts.scaleAll: 313 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value") 314 self.opts.scaleAll=True 315 316 if self.opts.time==None: 317 self.opts.time=samples.times 318 if self.opts.line==None: 319 self.opts.line=samples.lines() 320 for t in self.opts.time: 321 for l in self.opts.line: 322 plot=samples.getData(line=[l], 323 value=self.opts.field, 324 time=[t]) 325 oPlots.append(plot[:]) 326 if reference: 327 p=reference.getData(line=[l], 328 value=self.opts.field, 329 time=[t], 330 note=self.opts.refprefix+" ") 331 rPlots.append(p) 332 plot+=p 333 334 plots.append(plot) 335 336 elif self.opts.mode=="linesInOne": 337 if self.opts.field==None: 338 self.opts.field=samples.values() 339 if self.opts.time==None: 340 self.opts.time=samples.times() 341 for f in self.opts.field: 342 for t in self.opts.time: 343 plot=samples.getData(line=self.opts.line, 344 value=[f], 345 time=[t]) 346 oPlots.append(plot[:]) 347 348 if reference: 349 p=reference.getData(line=self.opts.line, 350 value=[f], 351 time=[t], 352 note=self.opts.refprefix+" ") 353 rPlots.append(p) 354 plot+=p 355 356 plots.append(plot) 357 358 elif self.opts.mode=="complete": 359 if self.opts.scaled and not self.opts.scaleAll: 360 warning("In mode '",self.opts.mode,"' all fields are scaled to the same value") 361 self.opts.scaleAll=True 362 363 plot=samples.getData(line=self.opts.line, 364 value=self.opts.field, 365 time=self.opts.time) 366 oPlots.append(plot[:]) 367 if reference: 368 p=reference.getData(line=self.opts.line, 369 value=self.opts.field, 370 time=self.opts.time, 371 note=self.opts.refprefix+" ") 372 plot+=p 373 rPlots.append(p) 374 375 plots.append(plot) 376 377 if self.opts.scaled: 378 if self.opts.scaleAll: 379 vRange=None 380 else: 381 vRanges={} 382 383 for p in plots: 384 for d in p: 385 mi,ma=d.range(component=self.opts.component) 386 nm=d.name 387 if not self.opts.scaleAll: 388 if nm in vRanges: 389 vRange=vRanges[nm] 390 else: 391 vRange=None 392 393 if vRange==None: 394 vRange=mi,ma 395 else: 396 vRange=min(vRange[0],mi),max(vRange[1],ma) 397 if not self.opts.scaleAll: 398 vRanges[nm]=vRange 399 400 result="set term png\n" 401 402 for p in plots: 403 if len(p)<1: 404 continue 405 406 name="" 407 408 if self.opts.namePrefix: 409 name+=self.opts.namePrefix+"_" 410 name+=self.opts.dirName 411 title=None 412 tIndex=times.index(p[0].time()) 413 414 # name+="_"+string.join(self.opts.line,"_") 415 416 if self.opts.mode=="separate": 417 name+="_%s" % (p[0].line()) 418 name+="_%s_%04d" % (p[0].name,tIndex) 419 title="%s at t=%f on %s" % (p[0].name,float(p[0].time()),p[0].line()) 420 elif self.opts.mode=="timesInOne": 421 name+="_%s" % (p[0].line()) 422 if self.opts.time!=None: 423 name+="_"+"_".join(["t="+t for t in self.opts.time]) 424 name+="_%s" % p[0].name 425 title="%s on %s" % (p[0].name,p[0].line()) 426 elif self.opts.mode=="fieldsInOne": 427 name+="_%s" % (p[0].line()) 428 if self.opts.field!=None: 429 name+="_"+string.join(self.opts.field,"_") 430 if self.opts.time!=None: 431 name+="_"+"_".join(["t="+t for t in self.opts.time]) 432 name+="_%04d" % tIndex 433 title="t=%f on %s" % (float(p[0].time()),p[0].line()) 434 elif self.opts.mode=="linesInOne": 435 name+="_%s" % (p[0].name) 436 if self.opts.line!=None: 437 name+="_"+string.join(self.opts.line,"_") 438 name+="_t=%f" % float(p[0].time()) 439 title="%s at t=%f" % (p[0].name,float(p[0].time())) 440 elif self.opts.mode=="complete": 441 pass 442 443 name+=".png" 444 if self.opts.pictureDest: 445 name=path.join(self.opts.pictureDest,name) 446 447 if self.opts.cleanFilename: 448 name=cleanFilename(name) 449 450 result+='set output "%s"\n' % name 451 if title!=None: 452 result+='set title "%s"\n' % title 453 454 result+="plot " 455 if self.opts.scaled: 456 if not self.opts.scaleAll: 457 vRange=vRanges[p[0].name] 458 459 # only scale if extremas are sufficiently different 460 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: 461 result+="[][%g:%g] " % vRange 462 463 first=True 464 465 for d in p: 466 if first: 467 first=False 468 else: 469 result+=", " 470 471 colSpec="%s" % (d.index+1) 472 if d.isVector(): 473 if self.opts.component: 474 colSpec="%d" % (d.index+1+self.opts.component) 475 else: 476 colSpec="(sqrt($%d**2+$%d**2+$%d**2))" % (d.index+1,d.index+2,d.index+3) 477 478 result+='"%s" using 1:%s ' % (d.file,colSpec) 479 480 title=d.note 481 if self.opts.mode=="separate": 482 title+="" 483 elif self.opts.mode=="timesInOne": 484 title+="t=%f" % float(d.time()) 485 elif self.opts.mode=="fieldsInOne": 486 title+="%s" % d.name 487 elif self.opts.mode=="linesInOne": 488 title+="t=%f" % float(d.time()) 489 elif self.opts.mode=="complete": 490 title+="%s at t=%f" % (d.name,float(d.time())) 491 492 if len(self.opts.line)>1: 493 title+=" on %s" % d.line() 494 495 if title=="": 496 result+="notitle " 497 else: 498 result+='title "%s" ' % title 499 500 result+="with %s " % self.opts.style 501 502 result+="\n" 503 504 if self.opts.csvFile: 505 tmp=sum(plots,[]) 506 c=tmp[0]() 507 for p in tmp[1:]: 508 try: 509 c+=p() 510 except WrongDataSize,e: 511 if self.opts.resampleReference: 512 sp=p() 513 for n in sp.names()[1:]: 514 data=c.resample(sp, 515 n, 516 extendData=self.opts.extendData) 517 try: 518 c.append(n,data) 519 except ValueError: 520 c.append(self.opts.refprefix+" "+n,data) 521 else: 522 self.warning("Try the --resample-option") 523 raise 524 525 c.writeCSV(self.opts.csvFile) 526 elif self.opts.compare or self.opts.metrics: 527 oPlots=[item for sublist in oPlots for item in sublist] 528 rPlots=[item for sublist in rPlots for item in sublist] 529 if len(rPlots)!=len(oPlots) and self.opts.compare: 530 self.error("Number of original data sets",len(oPlots), 531 "is not equal to the reference data sets", 532 len(rPlots)) 533 if len(rPlots)==0 and self.opts.metrics: 534 rPlots=[None]*len(oPlots) 535 536 for o,r in zip(oPlots,rPlots): 537 data=o() 538 if self.opts.compare: 539 if o.name!=r.name or o.index!=r.index: 540 self.error("Data from original",o.name,o.index, 541 "and reference",r.name,r.index, 542 "do not match") 543 ref=r() 544 else: 545 ref=None 546 for i,n in enumerate(data.names()): 547 if i==0: 548 continue 549 if self.opts.metrics: 550 print "Metrics for",o.name,"(Path:",o.file,")" 551 result=data.metrics(data.names()[i]) 552 print " Min :",result["min"] 553 print " Max :",result["max"] 554 print " Average :",result["average"] 555 print " Weighted average :",result["wAverage"] 556 if not self.opts.compare: 557 print "Data size:",data.size() 558 print " Time Range :",result["tMin"],result["tMax"] 559 if self.opts.compare: 560 print "Comparing",o.name,"with name",n,"(Path:",o.file,")" 561 result=data.compare(ref,data.names()[i]) 562 print " Max difference :",result["max"] 563 print " Average difference :",result["average"] 564 print " Weighted average :",result["wAverage"] 565 print "Data size:",data.size(),"Reference:",ref.size() 566 if not self.opts.metrics: 567 print " Time Range :",result["tMin"],result["tMax"] 568 569 print 570 else: 571 dest=sys.stdout 572 if self.opts.gnuplotFile: 573 dest=open(self.opts.gnuplotFile,"w") 574 575 dest.write(result)
576