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

Source Code for Module PyFoam.Applications.CaseReport

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/CaseReport.py 6230 2010-03-23T22:47:36.132303Z bgschaid  $  
  2  """ 
  3  Application class that implements pyFoamCasedReport.py 
  4  """ 
  5   
  6  import sys,string 
  7  from optparse import OptionGroup 
  8   
  9  from fnmatch import fnmatch 
 10   
 11  from PyFoamApplication import PyFoamApplication 
 12  from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory 
 13  from PyFoam.RunDictionary.BoundaryDict import BoundaryDict 
 14  from PyFoam.RunDictionary.MeshInformation import MeshInformation 
 15  from PyFoam.RunDictionary.ParsedParameterFile import PyFoamParserError,ParsedBoundaryDict,ParsedParameterFile 
 16   
 17  from PyFoam.Error import error,warning 
 18   
 19  from math import log10,ceil 
 20  from os import path 
 21   
22 -class CaseReport(PyFoamApplication):
23 - def __init__(self,args=None):
24 description=""" 25 Produces human-readable reports about a case. Attention: the amount of 26 information in the reports is limited. The truth is always in the 27 dictionary-files 28 """ 29 30 PyFoamApplication.__init__(self, 31 args=args, 32 description=description, 33 usage="%prog [options] <casedir>", 34 nr=1, 35 changeVersion=False, 36 interspersed=True)
37
38 - def addOptions(self):
39 report=OptionGroup(self.parser, 40 "Reports", 41 "What kind of reports should be produced") 42 self.parser.add_option_group(report) 43 select=OptionGroup(self.parser, 44 "Selection", 45 "Which data should be used for the reports") 46 self.parser.add_option_group(select) 47 internal=OptionGroup(self.parser, 48 "Internal", 49 "Details of the parser") 50 self.parser.add_option_group(internal) 51 output=OptionGroup(self.parser, 52 "Output", 53 "How Output should be generated") 54 self.parser.add_option_group(output) 55 56 output.add_option("--file", 57 action="store", 58 default=None, 59 dest="file", 60 help="Write the output to a file instead of the console") 61 62 report.add_option("--short-bc-report", 63 action="store_true", 64 default=False, 65 dest="shortBCreport", 66 help="Gives a short overview of the boundary-conditions in the case") 67 68 report.add_option("--long-bc-report", 69 action="store_true", 70 default=False, 71 dest="longBCreport", 72 help="Gives a full overview of the boundary-conditions in the case") 73 74 report.add_option("--dimensions", 75 action="store_true", 76 default=False, 77 dest="dimensions", 78 help="Show the dimensions of the fields") 79 80 report.add_option("--internal-field", 81 action="store_true", 82 default=False, 83 dest="internal", 84 help="Show the internal value of the fields (the initial conditions)") 85 86 report.add_option("--linear-solvers", 87 action="store_true", 88 default=False, 89 dest="linearSolvers", 90 help="Print the linear solvers and their tolerance") 91 92 report.add_option("--relaxation-factors", 93 action="store_true", 94 default=False, 95 dest="relaxationFactors", 96 help="Print the relaxation factors (if there are any)") 97 98 select.add_option("--time", 99 action="store", 100 type="float", 101 default=None, 102 dest="time", 103 help="Time to use as the basis for the reports") 104 105 select.add_option("--region", 106 dest="region", 107 default=None, 108 help="Do the report for a special region for multi-region cases") 109 110 select.add_option("--parallel", 111 action="store_true", 112 default=False, 113 dest="parallel", 114 help="Print the relaxation factors (if there are any)") 115 116 internal.add_option("--long-field-threshold", 117 action="store", 118 type="int", 119 default=100, 120 dest="longlist", 121 help="Fields that are longer than this won't be parsed, but read into memory (and compared as strings)") 122 123 select.add_option("--patches", 124 action="append", 125 default=None, 126 dest="patches", 127 help="Patches which should be processed (pattern, can be used more than once)") 128 129 select.add_option("--exclude-patches", 130 action="append", 131 default=None, 132 dest="expatches", 133 help="Patches which should not be processed (pattern, can be used more than once)") 134 135 report.add_option("--processor-matrix", 136 action="store_true", 137 default=False, 138 dest="processorMatrix", 139 help="Prints the matrix how many faces from one processor interact with another") 140 141 report.add_option("--case-size", 142 action="store_true", 143 default=False, 144 dest="caseSize", 145 help="Report the number of cells, points and faces in the case") 146 147 report.add_option("--decomposition", 148 action="store_true", 149 default=False, 150 dest="decomposition", 151 help="Reports the size of the parallel decomposition")
152
153 - def run(self):
154 if self.opts.file: 155 sys.stdout=open(self.opts.file,"w") 156 157 sol=SolutionDirectory(self.parser.getArgs()[0], 158 archive=None, 159 parallel=self.opts.parallel, 160 paraviewLink=False, 161 region=self.opts.region) 162 if self.opts.time: 163 try: 164 self.opts.time=sol.timeName(sol.timeIndex(self.opts.time,minTime=True)) 165 except IndexError: 166 error("The specified time",self.opts.time,"doesn't exist in the case") 167 print "Using time t="+self.opts.time+"\n" 168 169 needsPolyBoundaries=False 170 needsInitialTime=False 171 172 if self.opts.longBCreport: 173 needsPolyBoundaries=True 174 needsInitialTime=True 175 if self.opts.shortBCreport: 176 needsPolyBoundaries=True 177 needsInitialTime=True 178 if self.opts.dimensions: 179 needsInitialTime=True 180 if self.opts.internal: 181 needsInitialTime=True 182 if self.opts.decomposition: 183 needsPolyBoundaries=True 184 185 defaultProc=None 186 if self.opts.parallel: 187 defaultProc=0 188 189 if needsPolyBoundaries: 190 proc=None 191 boundary=BoundaryDict(sol.name, 192 region=self.opts.region, 193 time=self.opts.time, 194 processor=defaultProc) 195 196 boundMaxLen=0 197 boundaryNames=[] 198 for b in boundary: 199 if b.find("procBoundary")!=0: 200 boundaryNames.append(b) 201 if self.opts.patches!=None: 202 tmp=boundaryNames 203 boundaryNames=[] 204 for b in tmp: 205 for p in self.opts.patches: 206 if fnmatch(b,p): 207 boundaryNames.append(b) 208 break 209 210 if self.opts.expatches!=None: 211 tmp=boundaryNames 212 boundaryNames=[] 213 for b in tmp: 214 keep=True 215 for p in self.opts.expatches: 216 if fnmatch(b,p): 217 keep=False 218 break 219 if keep: 220 boundaryNames.append(b) 221 222 for b in boundaryNames: 223 boundMaxLen=max(boundMaxLen,len(b)) 224 boundaryNames.sort() 225 226 if self.opts.time==None: 227 procTime="constant" 228 else: 229 procTime=self.opts.time 230 231 if needsInitialTime: 232 fields={} 233 234 if self.opts.time==None: 235 try: 236 time=sol.timeName(0) 237 except IndexError: 238 error("There is no timestep in the case") 239 else: 240 time=self.opts.time 241 242 tDir=sol[time] 243 244 nameMaxLen=0 245 246 for f in tDir: 247 try: 248 fields[f.baseName()]=f.getContent(listLengthUnparsed=self.opts.longlist) 249 nameMaxLen=max(nameMaxLen,len(f.baseName())) 250 except PyFoamParserError,e: 251 warning("Couldn't parse",f.name,"because of an error:",e," -> skipping") 252 253 fieldNames=fields.keys() 254 fieldNames.sort() 255 256 if self.opts.caseSize: 257 print "Size of the case" 258 nFaces=0 259 nPoints=0 260 nCells=0 261 if self.opts.parallel: 262 procs=range(sol.nrProcs()) 263 print "Accumulated from",sol.nrProcs(),"processors" 264 else: 265 procs=[None] 266 print 267 268 for p in procs: 269 info=MeshInformation(sol.name, 270 processor=p, 271 time=self.opts.time) 272 nFaces+=info.nrOfFaces() 273 nPoints+=info.nrOfPoints() 274 try: 275 nCells+=info.nrOfCells() 276 except: 277 nCells="Not available" 278 print "Faces: \t",nFaces 279 print "Points: \t",nPoints 280 print "Cells: \t",nCells 281 282 if self.opts.decomposition: 283 if sol.nrProcs()<2: 284 print "This case is not decomposed" 285 return 286 287 print "Case is decomposed for",sol.nrProcs(),"processors" 288 289 nCells=[] 290 nFaces=[] 291 nPoints=[] 292 for p in sol.processorDirs(): 293 info=MeshInformation(sol.name, 294 processor=p, 295 time=self.opts.time) 296 nPoints.append(info.nrOfPoints()) 297 nFaces.append(info.nrOfFaces()) 298 nCells.append(info.nrOfCells()) 299 300 digits=int(ceil(log10(max(sol.nrProcs(), 301 max(nCells), 302 max(nFaces), 303 max(nPoints) 304 ))))+2 305 nameLen=max(len("Points"),boundMaxLen) 306 307 nrFormat ="%%%dd" % digits 308 nameFormat="%%%ds" % nameLen 309 310 print " "*nameLen,"|", 311 for i in range(sol.nrProcs()): 312 print nrFormat % i, 313 print 314 315 print "-"*(nameLen+3+(digits+1)*sol.nrProcs()) 316 317 print nameFormat % "Points","|", 318 for p in nPoints: 319 print nrFormat % p, 320 print 321 print nameFormat % "Faces","|", 322 for p in nFaces: 323 print nrFormat % p, 324 print 325 print nameFormat % "Cells","|", 326 for p in nCells: 327 print nrFormat % p, 328 print 329 330 print "-"*(nameLen+3+(digits+1)*sol.nrProcs()) 331 332 for b in boundaryNames: 333 print nameFormat % b,"|", 334 for p in sol.processorDirs(): 335 try: 336 nFaces= ParsedBoundaryDict(sol.boundaryDict(processor=p, 337 time=self.opts.time) 338 )[b]["nFaces"] 339 except KeyError: 340 nFaces=0 341 342 print nrFormat % nFaces, 343 print 344 345 if self.opts.longBCreport: 346 print "\nThe boundary conditions for t =",time 347 348 for b in boundaryNames: 349 print "\nBoundary: \t",b 350 bound=boundary[b] 351 print " type:\t",bound["type"], 352 if "physicalType" in bound: 353 print "( Physical:",bound["physicalType"],")", 354 print " \t Faces:",bound["nFaces"] 355 for fName in fieldNames: 356 print " ",fName, 357 f=fields[fName] 358 if "boundaryField" not in f: 359 print " "*(nameMaxLen-len(fName)+2)+": Not a field file" 360 elif b not in f["boundaryField"]: 361 print " "*(nameMaxLen-len(fName)+2)+": MISSING !!!" 362 else: 363 bf=f["boundaryField"][b] 364 maxKeyLen=0 365 for k in bf: 366 maxKeyLen=max(maxKeyLen,len(k)) 367 368 print " "*(nameMaxLen-len(fName)+2)+"type "+" "*(maxKeyLen-4)+": ",bf["type"] 369 for k in bf: 370 if k!="type": 371 print " "*(nameMaxLen+6),k," "*(maxKeyLen-len(k))+": ", 372 cont=str(bf[k]) 373 if cont.find("\n")>=0: 374 print cont[:cont.find("\n")],"..." 375 else: 376 print cont 377 378 if self.opts.shortBCreport: 379 print "\nTable of boundary conditions for t =",time 380 print 381 382 colLen = {} 383 types={} 384 hasPhysical=False 385 nameMaxLen=max(nameMaxLen,len("Patch Type")) 386 for b in boundary: 387 colLen[b]=max(len(b),len(boundary[b]["type"])) 388 colLen[b]=max(len(b),len(str(boundary[b]["nFaces"]))) 389 if "physicalType" in boundary[b]: 390 hasPhysical=True 391 nameMaxLen=max(nameMaxLen,len("Physical Type")) 392 colLen[b]=max(colLen[b],len(boundary[b]["physicalType"])) 393 394 types[b]={} 395 396 for fName in fields: 397 f=fields[fName] 398 try: 399 if b not in f["boundaryField"]: 400 types[b][fName]="MISSING" 401 else: 402 types[b][fName]=f["boundaryField"][b]["type"] 403 except KeyError: 404 types[b][fName]="Not a field" 405 406 colLen[b]=max(colLen[b],len(types[b][fName])) 407 408 print " "*(nameMaxLen), 409 nr=nameMaxLen+1 410 for b in boundaryNames: 411 print "| "+b+" "*(colLen[b]-len(b)), 412 nr+=colLen[b]+3 413 print 414 print "-"*nr 415 print "Patch Type"+" "*(nameMaxLen-len("Patch Type")), 416 for b in boundaryNames: 417 t=boundary[b]["type"] 418 print "| "+t+" "*(colLen[b]-len(t)), 419 print 420 if hasPhysical: 421 print "Physical Type"+" "*(nameMaxLen-len("Physical Type")), 422 for b in boundaryNames: 423 t="" 424 if "physicalType" in boundary[b]: 425 t=boundary[b]["physicalType"] 426 print "| "+t+" "*(colLen[b]-len(t)), 427 print 428 print "Length"+" "*(nameMaxLen-len("Length")), 429 for b in boundaryNames: 430 s=str(boundary[b]["nFaces"]) 431 print "| "+s+" "*(colLen[b]-len(s)), 432 print 433 print "-"*nr 434 for fName in fieldNames: 435 print fName+" "*(nameMaxLen-len(fName)), 436 for b in boundaryNames: 437 t=types[b][fName] 438 print "| "+t+" "*(colLen[b]-len(t)), 439 print 440 441 print 442 443 if self.opts.dimensions: 444 print "\nDimensions of fields for t =",time 445 print 446 447 head="Name"+" "*(nameMaxLen-len("Name"))+" : [kg m s K mol A cd]" 448 print head 449 print "-"*len(head) 450 for fName in fieldNames: 451 f=fields[fName] 452 try: 453 dim=f["dimensions"] 454 print fName+" "*(nameMaxLen-len(fName))+" :",dim 455 except KeyError: 456 print fName,"is not a field file" 457 458 if self.opts.internal: 459 print "\Internal value of fields for t =",time 460 print 461 462 head="Name"+" "*(nameMaxLen-len("Name"))+" : Value " 463 print head 464 print "-"*len(head) 465 for fName in fieldNames: 466 f=fields[fName] 467 468 print fName+" "*(nameMaxLen-len(fName))+" :", 469 470 try: 471 cont=str(f["internalField"]) 472 if cont.find("\n")>=0: 473 print cont[:cont.find("\n")],"..." 474 else: 475 print cont 476 except KeyError: 477 print "Not a field file" 478 479 if self.opts.processorMatrix: 480 if sol.nrProcs()<2: 481 print "This case is not decomposed" 482 483 return 484 485 matrix=[ [0,]*sol.nrProcs() for i in range(sol.nrProcs())] 486 487 for i,p in enumerate(sol.processorDirs()): 488 bound=ParsedBoundaryDict(path.join(sol.name,p,procTime,"polyMesh","boundary")) 489 for j in range(sol.nrProcs()): 490 name="procBoundary%dto%d" %(j,i) 491 name2="procBoundary%dto%d" %(i,j) 492 if name in bound: 493 matrix[i][j]=bound[name]["nFaces"] 494 if name2 in bound: 495 matrix[i][j]=bound[name2]["nFaces"] 496 497 print "Matrix of processor interactions (faces)" 498 print 499 500 digits=int(ceil(log10(sol.nrProcs())))+2 501 colDigits=int(ceil(log10(max(digits,max(max(matrix))))))+2 502 503 format="%%%dd" % digits 504 colFormat="%%%dd" % colDigits 505 506 print " "*(digits),"|", 507 for j in range(sol.nrProcs()): 508 print colFormat % j, 509 print 510 print "-"*(digits+3+(colDigits+1)*sol.nrProcs()) 511 512 for i,col in enumerate(matrix): 513 print format % i,"|", 514 for j,nr in enumerate(col): 515 print colFormat % matrix[i][j], 516 print 517 518 if self.opts.linearSolvers: 519 fvSol=ParsedParameterFile(path.join(sol.systemDir(),"fvSolution")) 520 allInfo={} 521 for sName in fvSol["solvers"]: 522 raw=fvSol["solvers"][sName] 523 info={} 524 info["solver"]=raw[0] 525 try: 526 info["tolerance"]=raw[1]["tolerance"] 527 except KeyError: 528 info["tolerance"]=1. 529 try: 530 info["relTol"]=raw[1]["relTol"] 531 except KeyError: 532 info["relTol"]=0. 533 534 allInfo[sName]=info 535 536 title="%15s | %15s | %10s | %8s" % ("name","solver","tolerance","relative") 537 print title 538 print "-"*len(title) 539 for n,i in allInfo.iteritems(): 540 print "%15s | %15s | %10g | %8g" % (n,i["solver"],i["tolerance"],i["relTol"]) 541 print 542 543 if self.opts.relaxationFactors: 544 fvSol=ParsedParameterFile(path.join(sol.systemDir(),"fvSolution")) 545 if "relaxationFactors" in fvSol: 546 title="%20s | %15s" % ("name","factor") 547 print title 548 print "-"*len(title) 549 for n,f in fvSol["relaxationFactors"].iteritems(): 550 print "%20s | %15g" % (n,f) 551 print 552 else: 553 print "No relaxation factors defined for this case"
554