1 """
2 Application-class that implements pyFoamListCases.py
3 """
4 from optparse import OptionGroup
5 from os import path,listdir,stat
6 import time,datetime
7 from stat import ST_MTIME
8 import string
9 import subprocess
10 import re
11 import os
12
13 from .PyFoamApplication import PyFoamApplication
14
15 from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
16 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,PyFoamParserError
17
18 from PyFoam import configuration
19
20 from PyFoam.ThirdParty.six import print_,iteritems,PY3
21
22 from PyFoam.Basics.Utilities import humanReadableSize
23
24 if PY3:
25 long=int
26
29 description="""\
30 List the valid OpenFOAM-cases in a number of directories along with
31 some basic information (number of timesteps, last timestep,
32 etc). Currently doesn't honor the parallel data
33 """
34 PyFoamApplication.__init__(self,
35 args=args,
36 description=description,
37 usage="%prog [<directories>]",
38 interspersed=True,
39 changeVersion=False,
40 nr=0,
41 exactNr=False)
42
43 sortChoices=["name","first","last","mtime","nrSteps","procs","diskusage","pFirst","pLast","nrParallel","nowTime","state","lastOutput","startedAt"]
44
46 what=OptionGroup(self.parser,
47 "What",
48 "Define what should be shown")
49 self.parser.add_option_group(what)
50
51 what.add_option("--dump",
52 action="store_true",
53 dest="dump",
54 default=False,
55 help="Dump the information as Python-dictionaries")
56
57 what.add_option("--disk-usage",
58 action="store_true",
59 dest="diskusage",
60 default=False,
61 help="Show the disk-usage of the case (in MB) - may take a long time")
62
63 what.add_option("--parallel-info",
64 action="store_true",
65 dest="parallel",
66 default=False,
67 help="Print information about parallel runs (if present): number of processors and processor first and last time. The mtime will be that of the processor-directories")
68
69 what.add_option("--no-state",
70 action="store_false",
71 dest="state",
72 default=True,
73 help="Don't read state-files")
74
75 what.add_option("--advanced-state",
76 action="store_true",
77 dest="advancedState",
78 default=False,
79 help="Additional state information (run started, last output seen)")
80
81 what.add_option("--estimate-end-time",
82 action="store_true",
83 dest="estimateEndTime",
84 default=False,
85 help="Print an estimated end time (calculated from the start time of the run, the current time and the current simulation time)")
86
87 what.add_option("--start-end-time",
88 action="store_true",
89 dest="startEndTime",
90 default=False,
91 help="Start and end time from the controlDict")
92
93 how=OptionGroup(self.parser,
94 "How",
95 "How the things should be shown")
96 self.parser.add_option_group(how)
97
98 how.add_option("--sort-by",
99 type="choice",
100 action="store",
101 dest="sort",
102 default=configuration().get("CommandOptionDefaults","sortListCases",default="name"),
103 choices=self.sortChoices,
104 help="Sort the cases by a specific key (Keys: "+string.join(self.sortChoices,", ")+") Default: %default")
105 how.add_option("--reverse-sort",
106 action="store_true",
107 dest="reverse",
108 default=False,
109 help="Sort in reverse order")
110 how.add_option("--relative-times",
111 action="store_true",
112 dest="relativeTime",
113 default=False,
114 help="Show the timestamps relative to the current time")
115
116 behave=OptionGroup(self.parser,
117 "Behaviour",
118 "Additional output etc")
119 self.parser.add_option_group(behave)
120
121 behave.add_option("--progress",
122 action="store_true",
123 dest="progress",
124 default=False,
125 help="Print the directories while they are being processed")
126
134
136 dirs=self.parser.getArgs()
137
138 if len(dirs)==0:
139 dirs=[path.curdir]
140
141 cData=[]
142 totalDiskusage=0
143
144 self.hasState=False
145
146 for d in dirs:
147 for n in listdir(d):
148 cName=path.join(d,n)
149 if path.isdir(cName):
150 try:
151 sol=SolutionDirectory(cName,archive=None,paraviewLink=False)
152 if sol.isValid():
153 if self.opts.progress:
154 print_("Processing",cName)
155
156 data={}
157
158 data["mtime"]=stat(cName)[ST_MTIME]
159 times=sol.getTimes()
160 try:
161 data["first"]=times[0]
162 except IndexError:
163 data["first"]="None"
164 try:
165 data["last"]=times[-1]
166 except IndexError:
167 data["last"]="None"
168 data["nrSteps"]=len(times)
169 data["procs"]=sol.nrProcs()
170 data["pFirst"]=-1
171 data["pLast"]=-1
172 data["nrParallel"]=-1
173 if self.opts.parallel:
174 pTimes=sol.getParallelTimes()
175 data["nrParallel"]=len(pTimes)
176 if len(pTimes)>0:
177 data["pFirst"]=pTimes[0]
178 data["pLast"]=pTimes[-1]
179 data["name"]=cName
180 data["diskusage"]=-1
181 if self.opts.diskusage:
182 try:
183 data["diskusage"]=int(
184 subprocess.Popen(
185 ["du","-sb",cName],
186 stdout=subprocess.PIPE,
187 stderr=open(os.devnull,"w")
188 ).communicate()[0].split()[0])
189 except IndexError:
190
191 data["diskusage"]=int(
192 subprocess.Popen(
193 ["du","-sk",cName],
194 stdout=subprocess.PIPE
195 ).communicate()[0].split()[0])*1024
196
197 totalDiskusage+=data["diskusage"]
198 if self.opts.parallel:
199 for f in listdir(cName):
200 if re.compile("processor[0-9]+").match(f):
201 data["mtime"]=max(stat(path.join(cName,f))[ST_MTIME],data["mtime"])
202
203 if self.opts.state:
204 try:
205 data["nowTime"]=float(self.readState(sol,"CurrentTime"))
206 except ValueError:
207 data["nowTime"]=None
208
209 try:
210 data["lastOutput"]=time.mktime(time.strptime(self.readState(sol,"LastOutputSeen")))
211 except ValueError:
212 data["lastOutput"]="nix"
213
214 data["state"]=self.readState(sol,"TheState")
215
216 if self.opts.state or self.opts.estimateEndTime:
217 try:
218 data["startedAt"]=time.mktime(time.strptime(self.readState(sol,"StartedAt")))
219 except ValueError:
220 data["startedAt"]="nix"
221
222 if self.opts.startEndTime or self.opts.estimateEndTime:
223 try:
224 ctrlDict=ParsedParameterFile(sol.controlDict(),doMacroExpansion=True)
225 except PyFoamParserError:
226
227 ctrlDict=ParsedParameterFile(sol.controlDict())
228
229 data["startTime"]=ctrlDict["startTime"]
230 data["endTime"]=ctrlDict["endTime"]
231
232 if self.opts.estimateEndTime:
233 data["endTimeEstimate"]=None
234 if self.readState(sol,"TheState")=="Running":
235 gone=time.time()-data["startedAt"]
236 try:
237 current=float(self.readState(sol,"CurrentTime"))
238 frac=(current-data["startTime"])/(data["endTime"]-data["startTime"])
239 except ValueError:
240 frac=0
241 if frac>0:
242 data["endTimeEstimate"]=data["startedAt"]+gone/frac
243
244 cData.append(data)
245 except OSError:
246 print_(cName,"is unreadable")
247
248 if self.opts.progress:
249 print_("Sorting data")
250
251 if self.opts.reverse:
252 cData.sort(lambda x,y:cmp(y[self.opts.sort],x[self.opts.sort]))
253 else:
254 cData.sort(lambda x,y:cmp(x[self.opts.sort],y[self.opts.sort]))
255
256 if len(cData)==0:
257 print_("No cases found")
258 return
259
260 if self.opts.dump:
261 print_(cData)
262 return
263
264 lens={}
265 for k in list(cData[0].keys()):
266 lens[k]=len(k)
267 for c in cData:
268 for k in ["mtime","lastOutput","startedAt","endTimeEstimate"]:
269 try:
270 if c[k]!=None:
271 if self.opts.relativeTime:
272 c[k]=datetime.timedelta(seconds=long(time.time()-c[k]))
273 else:
274 c[k]=time.asctime(time.localtime(c[k]))
275 except KeyError:
276 pass
277 except TypeError:
278 c[k]=None
279
280 try:
281 c["diskusage"]=humanReadableSize(c["diskusage"])
282 except KeyError:
283 pass
284
285 for k,v in iteritems(c):
286 lens[k]=max(lens[k],len(str(v)))
287
288 format=""
289 spec=["mtime"," | ","first"," - ","last"," (","nrSteps",") "]
290 if self.opts.parallel:
291 spec+=["| ","procs"," : ","pFirst"," - ","pLast"," (","nrParallel",") | "]
292 if self.opts.diskusage:
293 spec+=["diskusage"," | "]
294 if self.hasState:
295 spec+=["nowTime"," s ","state"," | "]
296 if self.opts.advancedState:
297 spec+=["lastOutput"," | ","startedAt"," | "]
298 if self.opts.estimateEndTime:
299 if not self.opts.advancedState:
300 spec+=["startedAt"," | "]
301 spec+=["endTimeEstimate"," | "]
302 if self.opts.startEndTime:
303 spec+=["startTime"," | ","endTime"," | "]
304
305 spec+=["name"]
306
307 for i,l in enumerate(spec):
308 if not l in list(cData[0].keys()):
309 format+=l
310 else:
311 if i<len(spec)-1:
312 format+="%%(%s)%ds" % (l,lens[l])
313 else:
314 format+="%%(%s)s" % (l)
315
316 if self.opts.progress:
317 print_("Printing\n\n")
318
319 header=format % dict(list(zip(list(cData[0].keys()),list(cData[0].keys()))))
320 print_(header)
321 print_("-"*len(header))
322
323 for d in cData:
324 for k in list(d.keys()):
325 d[k]=str(d[k])
326 print_(format % d)
327
328 if self.opts.diskusage:
329 print_("Total disk-usage:",humanReadableSize(totalDiskusage))
330
331
332
333