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

Source Code for Module PyFoam.Applications.SurfacePlot

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