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