1
2 """
3 Application class that implements pyFoamCasedReport.py
4 """
5
6 import sys,string
7
8 from fnmatch import fnmatch
9
10 from PyFoamApplication import PyFoamApplication
11 from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
12 from PyFoam.RunDictionary.BoundaryDict import BoundaryDict
13 from PyFoam.RunDictionary.MeshInformation import MeshInformation
14 from PyFoam.RunDictionary.ParsedParameterFile import PyFoamParserError,ParsedBoundaryDict
15
16 from PyFoam.Error import error,warning
17
18 from math import log10,ceil
19 from os import path
20
23 description="""
24 Produces human-readable reports about a case. Attention: the amount of
25 information in the reports is limited. The truth is always in the
26 dictionary-files
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
38 self.parser.add_option("--short-bc-report",
39 action="store_true",
40 default=False,
41 dest="shortBCreport",
42 help="Gives a short overview of the boundary-conditions in the case")
43
44 self.parser.add_option("--long-bc-report",
45 action="store_true",
46 default=False,
47 dest="longBCreport",
48 help="Gives a full overview of the boundary-conditions in the case")
49
50 self.parser.add_option("--dimensions",
51 action="store_true",
52 default=False,
53 dest="dimensions",
54 help="Show the dimensions of the fields")
55
56 self.parser.add_option("--internal-field",
57 action="store_true",
58 default=False,
59 dest="internal",
60 help="Show the internal value of the fields (the initial conditions)")
61
62 self.parser.add_option("--time",
63 action="store",
64 type="float",
65 default=None,
66 dest="time",
67 help="Time to use as the basis for the reports")
68
69 self.parser.add_option("--region",
70 dest="region",
71 default=None,
72 help="Do the report for a special region for multi-region cases")
73
74 self.parser.add_option("--long-field-threshold",
75 action="store",
76 type="int",
77 default=100,
78 dest="longlist",
79 help="Fields that are longer than this won't be parsed, but read into memory (nad compared as strings)")
80
81 self.parser.add_option("--patches",
82 action="append",
83 default=None,
84 dest="patches",
85 help="Patches which should be processed (pattern, can be used more than once)")
86
87 self.parser.add_option("--exclude-patches",
88 action="append",
89 default=None,
90 dest="expatches",
91 help="Patches which should not be processed (pattern, can be used more than once)")
92
93 self.parser.add_option("--processor-matrix",
94 action="store_true",
95 default=False,
96 dest="processorMatrix",
97 help="Prints the matrix how many faces from one processor interact with another")
98
99 self.parser.add_option("--case-size",
100 action="store_true",
101 default=False,
102 dest="caseSize",
103 help="Report the number of cells, points and faces in the case")
104
105 self.parser.add_option("--decomposition",
106 action="store_true",
107 default=False,
108 dest="decomposition",
109 help="Reports the size of the parallel decomposition")
110
112 sol=SolutionDirectory(self.parser.getArgs()[0],archive=None,paraviewLink=False,region=self.opts.region)
113
114 needsPolyBoundaries=False
115 needsInitialTime=False
116
117 if self.opts.longBCreport:
118 needsPolyBoundaries=True
119 needsInitialTime=True
120 if self.opts.shortBCreport:
121 needsPolyBoundaries=True
122 needsInitialTime=True
123 if self.opts.dimensions:
124 needsInitialTime=True
125 if self.opts.internal:
126 needsInitialTime=True
127 if self.opts.decomposition:
128 needsPolyBoundaries=True
129
130 if needsPolyBoundaries:
131 boundary=BoundaryDict(sol.name,region=self.opts.region)
132
133 boundMaxLen=0
134 boundaryNames=[]
135 for b in boundary:
136 boundaryNames.append(b)
137
138 if self.opts.patches!=None:
139 tmp=boundaryNames
140 boundaryNames=[]
141 for b in tmp:
142 for p in self.opts.patches:
143 if fnmatch(b,p):
144 boundaryNames.append(b)
145 break
146
147 if self.opts.expatches!=None:
148 tmp=boundaryNames
149 boundaryNames=[]
150 for b in tmp:
151 keep=True
152 for p in self.opts.expatches:
153 if fnmatch(b,p):
154 keep=False
155 break
156 if keep:
157 boundaryNames.append(b)
158
159 for b in boundaryNames:
160 boundMaxLen=max(boundMaxLen,len(b))
161 boundaryNames.sort()
162
163 if self.opts.time==None:
164 procTime="constant"
165 else:
166 procTime=sol.timeName(sol.timeIndex(self.opts.time,minTime=True))
167
168 if needsInitialTime:
169 fields={}
170
171 if self.opts.time==None:
172 time=sol.timeName(0)
173 else:
174 time=sol.timeName(sol.timeIndex(self.opts.time,minTime=True))
175
176
177
178 tDir=sol[time]
179
180 nameMaxLen=0
181
182 for f in tDir:
183 try:
184 fields[f.baseName()]=f.getContent(listLengthUnparsed=self.opts.longlist)
185 nameMaxLen=max(nameMaxLen,len(f.baseName()))
186 except PyFoamParserError,e:
187 warning("Couldn't parse",f.name,"because of an error:",e," -> skipping")
188
189 fieldNames=fields.keys()
190 fieldNames.sort()
191
192 if self.opts.caseSize:
193 print "Size of the case"
194 print
195 info=MeshInformation(sol.name)
196 print "Faces: \t",info.nrOfFaces()
197 print "Points: \t",info.nrOfPoints()
198 try:
199 print "Cells: \t",info.nrOfCells()
200 except:
201 print "Not available"
202
203 if self.opts.decomposition:
204 if sol.nrProcs()<2:
205 error("The case is not decomposed")
206 print "Case is decomposed for",sol.nrProcs(),"processors"
207
208 nCells=[]
209 nFaces=[]
210 nPoints=[]
211 for p in sol.processorDirs():
212 info=MeshInformation(sol.name,processor=p)
213 nPoints.append(info.nrOfPoints())
214 nFaces.append(info.nrOfFaces())
215 nCells.append(info.nrOfCells())
216
217 digits=int(ceil(log10(max(sol.nrProcs(),
218 max(nCells),
219 max(nFaces),
220 max(nPoints)
221 ))))+2
222 nameLen=max(len("Points"),boundMaxLen)
223
224 nrFormat ="%%%dd" % digits
225 nameFormat="%%%ds" % nameLen
226
227 print " "*nameLen,"|",
228 for i in range(sol.nrProcs()):
229 print nrFormat % i,
230 print
231
232 print "-"*(nameLen+3+(digits+1)*sol.nrProcs())
233
234 print nameFormat % "Points","|",
235 for p in nPoints:
236 print nrFormat % p,
237 print
238 print nameFormat % "Faces","|",
239 for p in nFaces:
240 print nrFormat % p,
241 print
242 print nameFormat % "Cells","|",
243 for p in nCells:
244 print nrFormat % p,
245 print
246
247 print "-"*(nameLen+3+(digits+1)*sol.nrProcs())
248
249 for b in boundaryNames:
250 print nameFormat % b,"|",
251 for p in sol.processorDirs():
252 print nrFormat % ParsedBoundaryDict(sol.boundaryDict(processor=p))[b]["nFaces"],
253 print
254
255 if self.opts.longBCreport:
256 print "\nThe boundary conditions for t =",time
257
258 for b in boundaryNames:
259 print "\nBoundary: \t",b
260 bound=boundary[b]
261 print " type:\t",bound["type"],
262 if "physicalType" in bound:
263 print "( Physical:",bound["physicalType"],")",
264 print " \t Faces:",bound["nFaces"]
265 for fName in fieldNames:
266 print " ",fName,
267 f=fields[fName]
268 if b not in f["boundaryField"]:
269 print " "*(nameMaxLen-len(fName)+2)+": MISSING !!!"
270 else:
271 bf=f["boundaryField"][b]
272 maxKeyLen=0
273 for k in bf:
274 maxKeyLen=max(maxKeyLen,len(k))
275
276 print " "*(nameMaxLen-len(fName)+2)+"type "+" "*(maxKeyLen-4)+": ",bf["type"]
277 for k in bf:
278 if k!="type":
279 print " "*(nameMaxLen+6),k," "*(maxKeyLen-len(k))+": ",
280 cont=str(bf[k])
281 if cont.find("\n")>=0:
282 print cont[:cont.find("\n")],"..."
283 else:
284 print cont
285
286 if self.opts.shortBCreport:
287 print "\nTable of boundary conditions for t =",time
288 print
289
290 colLen = {}
291 types={}
292 hasPhysical=False
293 nameMaxLen=max(nameMaxLen,len("Patch Type"))
294 for b in boundary:
295 colLen[b]=max(len(b),len(boundary[b]["type"]))
296 colLen[b]=max(len(b),len(str(boundary[b]["nFaces"])))
297 if "physicalType" in boundary[b]:
298 hasPhysical=True
299 nameMaxLen=max(nameMaxLen,len("Physical Type"))
300 colLen[b]=max(colLen[b],len(boundary[b]["physicalType"]))
301
302 types[b]={}
303
304 for fName in fields:
305 f=fields[fName]
306 if b not in f["boundaryField"]:
307 types[b][fName]="MISSING"
308 else:
309 types[b][fName]=f["boundaryField"][b]["type"]
310 colLen[b]=max(colLen[b],len(types[b][fName]))
311
312 print " "*(nameMaxLen),
313 nr=nameMaxLen+1
314 for b in boundaryNames:
315 print "| "+b+" "*(colLen[b]-len(b)),
316 nr+=colLen[b]+3
317 print
318 print "-"*nr
319 print "Patch Type"+" "*(nameMaxLen-len("Patch Type")),
320 for b in boundaryNames:
321 t=boundary[b]["type"]
322 print "| "+t+" "*(colLen[b]-len(t)),
323 print
324 if hasPhysical:
325 print "Physical Type"+" "*(nameMaxLen-len("Physical Type")),
326 for b in boundaryNames:
327 t=""
328 if "physicalType" in boundary[b]:
329 t=boundary[b]["physicalType"]
330 print "| "+t+" "*(colLen[b]-len(t)),
331 print
332 print "Length"+" "*(nameMaxLen-len("Length")),
333 for b in boundaryNames:
334 s=str(boundary[b]["nFaces"])
335 print "| "+s+" "*(colLen[b]-len(s)),
336 print
337 print "-"*nr
338 for fName in fieldNames:
339 print fName+" "*(nameMaxLen-len(fName)),
340 for b in boundaryNames:
341 t=types[b][fName]
342 print "| "+t+" "*(colLen[b]-len(t)),
343 print
344
345 print
346
347 if self.opts.dimensions:
348 print "\nDimensions of fields for t =",time
349 print
350
351 head="Name"+" "*(nameMaxLen-len("Name"))+" : [kg m s K mol A cd]"
352 print head
353 print "-"*len(head)
354 for fName in fieldNames:
355 f=fields[fName]
356
357 print fName+" "*(nameMaxLen-len(fName))+" :",f["dimensions"]
358
359 if self.opts.internal:
360 print "\Internal value of fields for t =",time
361 print
362
363 head="Name"+" "*(nameMaxLen-len("Name"))+" : Value "
364 print head
365 print "-"*len(head)
366 for fName in fieldNames:
367 f=fields[fName]
368
369 print fName+" "*(nameMaxLen-len(fName))+" :",
370
371 cont=str(f["internalField"])
372 if cont.find("\n")>=0:
373 print cont[:cont.find("\n")],"..."
374 else:
375 print cont
376
377 if self.opts.processorMatrix:
378 if sol.nrProcs()<2:
379 error("The case is not decomposed")
380
381 matrix=[ [0,]*sol.nrProcs() for i in range(sol.nrProcs())]
382
383 for i,p in enumerate(sol.processorDirs()):
384 bound=ParsedBoundaryDict(path.join(sol.name,p,procTime,"polyMesh","boundary"))
385 for j in range(sol.nrProcs()):
386 name="procBoundary%dto%d" %(i,j)
387 if name in bound:
388 matrix[i][j]=bound[name]["nFaces"]
389
390 print "Matrix of processor interactions (faces)"
391 print
392
393 digits=int(ceil(log10(sol.nrProcs())))+2
394 colDigits=int(ceil(log10(max(digits,max(max(matrix))))))+2
395
396 format="%%%dd" % digits
397 colFormat="%%%dd" % colDigits
398
399 print " "*(digits),"|",
400 for j in range(sol.nrProcs()):
401 print colFormat % j,
402 print
403 print "-"*(digits+3+(colDigits+1)*sol.nrProcs())
404
405 for i,col in enumerate(matrix):
406 print format % i,"|",
407 for j,nr in enumerate(col):
408 print colFormat % matrix[i][j],
409 print
410