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

Source Code for Module PyFoam.Applications.SurfacePlot

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/SurfacePlot.py 6179 2010-02-12T13:34:04.618848Z bgschaid  $  
  2  """ 
  3  Application class that implements pyFoamSurfacePlot.py 
  4  """ 
  5   
  6  import sys,string 
  7  from os import path 
  8  from optparse import OptionGroup 
  9  from copy import copy 
 10  from math import ceil,sqrt 
 11   
 12  from PyFoamApplication import PyFoamApplication 
 13  from PyFoam.RunDictionary.SurfaceDirectory import SurfaceDirectory 
 14   
 15  from PyFoam.Error import error,warning 
 16   
 17  from PlotHelpers import cleanFilename 
 18   
19 -class SurfacePlot(PyFoamApplication):
20 - def __init__(self,args=None):
21 description=""" 22 Searches for sampled surface in the VTK-format in a directory and makes 23 pictures from them 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("--surface", 41 action="append", 42 default=None, 43 dest="surface", 44 help="The sampled surface for which the 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="surfaces", 53 dest="dirName", 54 help="Alternate name for the directory with the samples (Default: %default)") 55 56 time=OptionGroup(self.parser, 57 "Time", 58 "Select the times to plot") 59 self.parser.add_option_group(time) 60 61 time.add_option("--time", 62 action="append", 63 default=None, 64 dest="time", 65 help="The times that are plotted (can be used more than once). If none are specified all found times are used") 66 time.add_option("--min-time", 67 action="store", 68 type="float", 69 default=None, 70 dest="minTime", 71 help="The smallest time that should be used") 72 time.add_option("--max-time", 73 action="store", 74 type="float", 75 default=None, 76 dest="maxTime", 77 help="The biggest time that should be used") 78 time.add_option("--fuzzy-time", 79 action="store_true", 80 default=False, 81 dest="fuzzyTime", 82 help="Try to find the next timestep if the time doesn't match exactly") 83 84 output=OptionGroup(self.parser, 85 "Appearance", 86 "How it should be plotted") 87 self.parser.add_option_group(output) 88 89 output.add_option("--unscaled", 90 action="store_false", 91 dest="scaled", 92 default=True, 93 help="Don't scale a value to the same range for all plots") 94 output.add_option("--interpolate-to-point", 95 action="store_true", 96 dest="toPoint", 97 default=False, 98 help="Plot data interpolated to point values (although the real truth lies in the cells)") 99 output.add_option("--scale-all", 100 action="store_true", 101 dest="scaleAll", 102 default=False, 103 help="Use the same scale for all fields (else use one scale for each field)") 104 output.add_option("--picture-destination", 105 action="store", 106 dest="pictureDest", 107 default=None, 108 help="Directory the pictures should be stored to") 109 output.add_option("--name-prefix", 110 action="store", 111 dest="namePrefix", 112 default=None, 113 help="Prefix to the picture-name") 114 output.add_option("--clean-filename", 115 action="store_true", 116 dest="cleanFilename", 117 default=False, 118 help="Clean filenames so that they can be used in HTML or Latex-documents") 119 120 colorMaps=["blueToRed","redToBlue","blackToWhite","redToWhite"] 121 # colorMaps.append("experimental") 122 123 output.add_option("--color-map", 124 type="choice", 125 dest="colorMap", 126 default="blueToRed", 127 choices=colorMaps, 128 help="Sets the used colormap to one of "+string.join(colorMaps,", ")+" with the default: %default") 129 130 data.add_option("--info", 131 action="store_true", 132 dest="info", 133 default=False, 134 help="Print info about the sampled data and exit") 135 136 camera=OptionGroup(self.parser, 137 "Camera", 138 "How to look at things") 139 self.parser.add_option_group(camera) 140 camera.add_option("--no-auto-camera", 141 action="store_false", 142 dest="autoCamera", 143 default=True, 144 help="The position of the camera should not be determined automagically") 145 camera.add_option("--dolly-factor", 146 action="store", 147 dest="dollyFactor", 148 type="float", 149 default=1, 150 help="The dolly-factor used to focus the camera: %default") 151 camera.add_option("--width-of-bitmap", 152 action="store", 153 type="int", 154 dest="width", 155 default=720, 156 help="The width that the render-window should have. Default: %default") 157 camera.add_option("--height-of-bitmap", 158 action="store", 159 dest="height", 160 type="int", 161 default=None, 162 help="The height that the render-window should have. If unspecified it is determined from the size of the data") 163 camera.add_option("--focal-point-offset", 164 action="store", 165 dest="focalOffset", 166 default="0,0,0", 167 help="Offset of the focal point from the center of the data. Only used in manual-camera mode. Default: %default") 168 camera.add_option("--camera-offset", 169 action="store", 170 dest="cameraOffset", 171 default="0,0,1", 172 help="Offset of the position of the camera from the center of the data. Only used in manual-camera mode. Default: %default") 173 camera.add_option("--up-direction", 174 action="store", 175 dest="upDirection", 176 default="0,1,0", 177 help="Which direction is up. Only used in manual-camera mode. Default: %default") 178 camera.add_option("--report-camera", 179 action="store_true", 180 dest="reportCamera", 181 default=False, 182 help="Report the used settings for the camera") 183 184 behave=OptionGroup(self.parser, 185 "Behaviour", 186 "How the program affects its environment") 187 self.parser.add_option_group(behave) 188 behave.add_option("--offscreen", 189 action="store_true", 190 dest="offscreen", 191 default=False, 192 help="Try to render the image offscreen (without a window)") 193 behave.add_option("--silent", 194 action="store_true", 195 dest="silent", 196 default=False, 197 help="Don't write progress to the terminal")
198
199 - def setupPipeline(self,fName):
200 if self.opts.offscreen: 201 grap=vtk.vtkGraphicsFactory() 202 grap.SetOffScreenOnlyMode(1) 203 grap.SetUseMesaClasses(1) 204 img=vtk.vtkImagingFactory() 205 img.SetUseMesaClasses(1) 206 207 self.reader = vtk.vtkDataSetReader() 208 self.reader.SetFileName(fName) 209 self.output = self.reader.GetOutput() 210 if self.opts.toPoint: 211 self.toPoint = vtk.vtkCellDataToPointData() 212 self.surfMapper = vtk.vtkDataSetMapper() 213 self.surfMapper.SetColorModeToMapScalars() 214 self.lut = vtk.vtkLookupTable() 215 if self.opts.colorMap=="blueToRed": 216 self.lut.SetHueRange(0.667,0) 217 elif self.opts.colorMap=="redToBlue": 218 self.lut.SetHueRange(0,0.667) 219 elif self.opts.colorMap=="blackToWhite": 220 self.lut.SetHueRange(1,1) 221 self.lut.SetValueRange(0,1) 222 self.lut.SetSaturationRange(0,0) 223 elif self.opts.colorMap=="redToWhite": 224 self.lut.SetHueRange(0,0.2) 225 self.lut.SetValueRange(1,1) 226 self.lut.SetSaturationRange(1,0.2) 227 else: 228 self.warning("Unknown colormap",self.opts.colorMap) 229 230 self.surfMapper.SetLookupTable(self.lut) 231 self.surfActor = vtk.vtkActor() 232 self.surfActor.SetMapper(self.surfMapper) 233 self.textActor = vtk.vtkTextActor() 234 self.textActor.SetDisplayPosition(90, 50) 235 self.textActor.SetTextScaleModeToViewport() 236 self.textActor.SetWidth(0.75) 237 238 self.barActor = vtk.vtkScalarBarActor() 239 self.barActor.SetLookupTable(self.lut) 240 self.barActor.SetDisplayPosition(90, 300) 241 self.barActor.SetOrientationToHorizontal() 242 self.barActor.SetHeight(0.15) 243 self.barActor.SetWidth(0.75) 244 245 # self.axes=vtk.vtkCubeAxesActor() 246 # self.axes.SetFlyModeToClosestTriad() 247 # self.axes.SetCornerOffset(0.1) 248 # self.axes.SetXLabelFormat("%6.1f") 249 # self.axes.SetYLabelFormat("%6.1f") 250 # self.axes.SetZLabelFormat("%6.1f") 251 # Create graphics stuff 252 self.ren = vtk.vtkRenderer() 253 self.renWin = vtk.vtkRenderWindow() 254 if self.opts.offscreen: 255 self.renWin.SetOffScreenRendering(1) 256 self.renWin.AddRenderer(self.ren) 257 258 self.ren.AddActor(self.surfActor) 259 self.ren.AddActor2D(self.textActor) 260 self.ren.AddActor2D(self.barActor) 261 # self.ren.AddViewProp(self.axes) 262 263 # self.axes.SetCamera(self.ren.GetActiveCamera()) 264 265 self.ren.SetBackground(0.7, 0.7, 0.7) 266 267 self.hasPipeline=True
268
269 - def setFilename(self,fName):
270 if not self.hasPipeline: 271 self.setupPipeline(fName) 272 else: 273 self.reader.SetFileName(fName) 274 275 self.reader.Update() 276 self.output = self.reader.GetOutput() 277 if self.opts.toPoint: 278 self.toPoint.SetInput(self.output) 279 self.surfMapper.SetInput(self.toPoint.GetOutput()) 280 else: 281 self.surfMapper.SetInput(self.output) 282 self.cData=self.output.GetCellData() 283 self.cData.SetScalars(self.cData.GetArray(0)) 284 self.surfMapper.SetScalarRange(self.reader.GetOutput().GetScalarRange())
285
286 - def setRange(self,rng):
287 self.surfMapper.SetScalarRange(rng)
288
289 - def setTitles(self,title,bar):
290 self.textActor.SetInput(title) 291 self.barActor.SetTitle(bar)
292
293 - def getCurrentRange(self):
294 return self.reader.GetOutput().GetScalarRange()
295
296 - def getVector(self,opt):
297 return map(float,opt.split(','))
298
299 - def writePicture(self,fName):
300 self.ren.ResetCamera() 301 302 xMin,xMax,yMin,yMax,zMin,zMax=self.output.GetBounds() 303 # self.axes.SetBounds(self.output.GetBounds()) 304 boundRange=[(xMax-xMin,0), 305 (yMax-yMin,1), 306 (zMax-zMin,2)] 307 boundRange.sort(lambda a,b:cmp(b[0],a[0])) 308 focalPoint=[0.5*(xMax+xMin),0.5*(yMax+yMin),0.5*(zMax+zMin)] 309 position=copy(focalPoint) 310 if self.opts.autoCamera: 311 ratio=max(0.2,boundRange[1][0]/max(boundRange[0][0],1e-10)) 312 self.opts.height=int(self.opts.width*ratio)+70 313 camOffset=[0,0,0] 314 camOffset[boundRange[2][1]]=boundRange[1][0]*3 315 up=[0,0,0] 316 up[boundRange[1][1]]=1. 317 else: 318 if self.opts.height==None: 319 self.opts.height=int(self.opts.width/sqrt(2)) 320 offset=self.getVector(self.opts.focalOffset) 321 for i in range(3): 322 focalPoint[i]+=offset[i] 323 camOffset=self.getVector(self.opts.cameraOffset) 324 up=self.getVector(self.opts.upDirection) 325 326 for i in range(3): 327 position[i]+=camOffset[i] 328 329 if self.opts.reportCamera: 330 print "Picture size:",self.opts.width,self.opts.height 331 print "Data bounds:",xMin,xMax,yMin,yMax,zMin,zMax 332 print "Focal point:",focalPoint 333 print "Up-direction:",up 334 print "Camera position:",position 335 336 self.renWin.SetSize(self.opts.width,self.opts.height) 337 self.barActor.SetDisplayPosition(int(self.opts.width*0.124), 20) 338 self.textActor.SetDisplayPosition(int(self.opts.width*0.124),self.opts.height-30) 339 self.ren.GetActiveCamera().SetFocalPoint(focalPoint) 340 self.ren.GetActiveCamera().SetViewUp(up) 341 self.ren.GetActiveCamera().SetPosition(position) 342 self.ren.GetActiveCamera().Dolly(self.opts.dollyFactor) 343 self.ren.ResetCameraClippingRange() 344 345 self.renWin.Render() 346 347 self.renderLarge = vtk.vtkRenderLargeImage() 348 self.renderLarge.SetInput(self.ren) 349 self.renderLarge.SetMagnification(1) 350 351 self.writer = vtk.vtkPNGWriter() 352 self.writer.SetInputConnection(self.renderLarge.GetOutputPort()) 353 354 self.writer.SetFileName(fName) 355 self.writer.Write()
356
357 - def run(self):
358 global vtk 359 import vtk 360 361 caseName=path.basename(path.abspath(self.parser.getArgs()[0])) 362 samples=SurfaceDirectory(self.parser.getArgs()[0],dirName=self.opts.dirName) 363 self.hasPipeline=False 364 365 if self.opts.info: 366 print "Times : ",samples.times 367 print "Surfaces : ",samples.surfaces() 368 print "Values : ",samples.values() 369 sys.exit(0) 370 371 surfaces=samples.surfaces() 372 times=samples.times 373 values=samples.values() 374 375 if self.opts.surface==None: 376 # error("At least one line has to be specified. Found were",samples.lines()) 377 self.opts.surface=surfaces 378 else: 379 for l in self.opts.surface: 380 if l not in surfaces: 381 error("The line",l,"does not exist in",lines) 382 383 if self.opts.maxTime or self.opts.minTime: 384 if self.opts.time: 385 error("Times",self.opts.time,"and range [",self.opts.minTime,",",self.opts.maxTime,"] set: contradiction") 386 self.opts.time=[] 387 if self.opts.maxTime==None: 388 self.opts.maxTime= 1e20 389 if self.opts.minTime==None: 390 self.opts.minTime=-1e20 391 392 for t in times: 393 if float(t)<=self.opts.maxTime and float(t)>=self.opts.minTime: 394 self.opts.time.append(t) 395 396 if len(self.opts.time)==0: 397 error("No times in range [",self.opts.minTime,",",self.opts.maxTime,"] found: ",times) 398 elif self.opts.time: 399 iTimes=self.opts.time 400 self.opts.time=[] 401 for t in iTimes: 402 if t in samples.times: 403 self.opts.time.append(t) 404 elif self.opts.fuzzyTime: 405 tf=float(t) 406 use=None 407 dist=1e20 408 for ts in samples.times: 409 if abs(tf-float(ts))<dist: 410 use=ts 411 dist=abs(tf-float(ts)) 412 if use and use not in self.opts.time: 413 self.opts.time.append(use) 414 else: 415 self.warning("Time",t,"not found in the sample-times. Use option --fuzzy") 416 417 if not self.opts.silent: 418 print "Getting data about plots" 419 plots=[] 420 421 if self.opts.time==None: 422 self.opts.time=samples.times 423 elif len(self.opts.time)==0: 424 self.error("No times specified. Exiting") 425 if self.opts.field==None: 426 self.opts.field=samples.values() 427 for s in self.opts.surface: 428 for t in self.opts.time: 429 for f in self.opts.field: 430 plt=samples.getData(surface=[s], 431 value=[f], 432 time=[t]) 433 if plt: 434 plots+=plt 435 436 vRanges=None 437 if self.opts.scaled: 438 if not self.opts.silent: 439 print "Getting ranges" 440 if self.opts.scaleAll: 441 vRange=None 442 else: 443 vRanges={} 444 445 for p in plots: 446 f,tm,surf,nm=p 447 self.setFilename(f) 448 449 mi,ma=self.getCurrentRange() 450 if not self.opts.scaleAll: 451 if nm in vRanges: 452 vRange=vRanges[nm] 453 else: 454 vRange=None 455 456 if vRange==None: 457 vRange=mi,ma 458 else: 459 vRange=min(vRange[0],mi),max(vRange[1],ma) 460 if not self.opts.scaleAll: 461 vRanges[nm]=vRange 462 463 for p in plots: 464 f,time,surf,nm=p 465 466 name="" 467 if self.opts.namePrefix: 468 name+=self.opts.namePrefix+"_" 469 name+=self.opts.dirName 470 tIndex=times.index(time) 471 472 name+="_"+surf 473 474 name+="_%s_%04d" % (nm,tIndex) 475 title="%s : %s - %s t=%f" % (caseName,self.opts.dirName,surf,float(time)) 476 477 name+=".png" 478 if self.opts.cleanFilename: 479 name=cleanFilename(name) 480 481 if self.opts.pictureDest: 482 name=path.join(self.opts.pictureDest,name) 483 484 self.setFilename(f) 485 if self.opts.scaleAll: 486 if vRange: 487 self.setRange(vRange) 488 else: 489 if vRanges: 490 if nm in vRanges: 491 self.setRange(vRanges[nm]) 492 493 self.setTitles(title,nm) 494 495 if not self.opts.silent: 496 print "Writing picture",name 497 498 self.writePicture(name)
499