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