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

Source Code for Module PyFoam.Applications.ListCases

  1  """ 
  2  Application-class that implements pyFoamListCases.py 
  3  """ 
  4  from optparse import OptionGroup 
  5  from os import path,listdir,stat 
  6  from glob import glob 
  7  from PyFoam.ThirdParty.six.moves import cPickle as pickle 
  8  from PyFoam.ThirdParty.six import string_types 
  9  import time,datetime 
 10  from stat import ST_MTIME 
 11  import re 
 12  import os 
 13   
 14  from .PyFoamApplication import PyFoamApplication 
 15   
 16  from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory 
 17  from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,PyFoamParserError 
 18   
 19  from PyFoam import configuration 
 20   
 21  from PyFoam.ThirdParty.six import print_,iteritems,PY3 
 22   
 23  from PyFoam.Basics.Utilities import humanReadableSize,diskUsage 
 24   
 25  if PY3: 
 26      long=int 
 27   
28 -class ListCases(PyFoamApplication):
29 - def __init__(self, 30 args=None, 31 **kwargs):
32 description="""\ 33 List the valid OpenFOAM-cases in a number of directories along with 34 some basic information (number of timesteps, last timestep, 35 etc). Currently doesn't honor the parallel data 36 """ 37 PyFoamApplication.__init__(self, 38 args=args, 39 description=description, 40 usage="%prog [<directories>]", 41 interspersed=True, 42 changeVersion=False, 43 nr=0, 44 exactNr=False, 45 **kwargs)
46 47 sortChoices=["name","first","last","mtime","nrSteps","procs","diskusage","pFirst","pLast","nrParallel","nowTime","state","lastOutput","startedAt"] 48
49 - def addOptions(self):
50 what=OptionGroup(self.parser, 51 "What", 52 "Define what should be shown") 53 self.parser.add_option_group(what) 54 55 what.add_option("--dump", 56 action="store_true", 57 dest="dump", 58 default=False, 59 help="Dump the information as Python-dictionaries") 60 61 what.add_option("--disk-usage", 62 action="store_true", 63 dest="diskusage", 64 default=False, 65 help="Show the disk-usage of the case (in MB) - may take a long time") 66 67 what.add_option("--parallel-info", 68 action="store_true", 69 dest="parallel", 70 default=False, 71 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") 72 73 what.add_option("--no-state", 74 action="store_false", 75 dest="state", 76 default=True, 77 help="Don't read state-files") 78 79 what.add_option("--advanced-state", 80 action="store_true", 81 dest="advancedState", 82 default=False, 83 help="Additional state information (run started, last output seen)") 84 85 what.add_option("--estimate-end-time", 86 action="store_true", 87 dest="estimateEndTime", 88 default=False, 89 help="Print an estimated end time (calculated from the start time of the run, the current time and the current simulation time)") 90 91 what.add_option("--start-end-time", 92 action="store_true", 93 dest="startEndTime", 94 default=False, 95 help="Start and end time from the controlDict") 96 97 what.add_option("--custom-data", 98 action="append", 99 dest="customData", 100 default=[], 101 help="Specification of additional data that is read from the pickled data-sets. The format is 'name=spec1::spec2::...' where 'name' is the name under which the data ist shown and 'specN' are the dictionary keys under which the data is accessed. If only 'spec1::spec2::..' is given then a name of the form 'CustomN' will be used. Can be specified more than once") 102 103 what.add_option("--solver-name-for-custom-data", 104 action="store", 105 dest="solverNameForCustom", 106 default=None, 107 help="This is used if '--custom-data' is specified as the data will be searched in 'PyFoamRunner.<solver name>.analyzed'. If unset then the utility will try to automatically determine the name of the solver which might be wrong") 108 109 how=OptionGroup(self.parser, 110 "How", 111 "How the things should be shown") 112 self.parser.add_option_group(how) 113 114 how.add_option("--sort-by", 115 type="choice", 116 action="store", 117 dest="sort", 118 default=configuration().get("CommandOptionDefaults","sortListCases",default="name"), 119 choices=self.sortChoices, 120 help="Sort the cases by a specific key (Keys: "+", ".join(self.sortChoices)+") Default: %default") 121 how.add_option("--reverse-sort", 122 action="store_true", 123 dest="reverse", 124 default=False, 125 help="Sort in reverse order") 126 how.add_option("--relative-times", 127 action="store_true", 128 dest="relativeTime", 129 default=False, 130 help="Show the timestamps relative to the current time") 131 132 behave=OptionGroup(self.parser, 133 "Behaviour", 134 "Additional output etc") 135 self.parser.add_option_group(behave) 136 137 behave.add_option("--progress", 138 action="store_true", 139 dest="progress", 140 default=False, 141 help="Print the directories while they are being processed")
142
143 - def readState(self,sol,sFile,default=""):
144 fName=path.join(sol.name,"PyFoamState."+sFile) 145 if not path.exists(fName): 146 return default 147 else: 148 self.hasState=True 149 return open(fName).read().strip()
150
151 - def run(self):
152 dirs=self.parser.getArgs() 153 154 if len(dirs)==0: 155 dirs=[path.curdir] 156 157 cData=[] 158 totalDiskusage=0 159 useSolverInData=False 160 161 self.hasState=False 162 163 customData=[] 164 for i,c in enumerate(self.opts.customData): 165 lst=c.split("=") 166 if len(lst)==2: 167 name,spec=lst 168 name+="_" # Make sure that there is no collision with standard-names 169 elif len(lst)==1: 170 name,spec="Custom%d" % (i+1),c 171 else: 172 self.error("Custom specification",c,"does not fit the pattern 'name=subs1::subs2::..'") 173 customData.append((name,spec.split("::"))) 174 175 if len(customData)>0 and not self.opts.solverNameForCustom: 176 self.warning("Parameter '--solver-name-for-custom-data' should be set if '--custom-data' is used") 177 useSolverInData=True 178 179 for d in dirs: 180 for n in listdir(d): 181 cName=path.join(d,n) 182 if path.isdir(cName): 183 try: 184 sol=SolutionDirectory(cName,archive=None,paraviewLink=False) 185 if sol.isValid(): 186 if self.opts.progress: 187 print_("Processing",cName) 188 189 data={} 190 191 data["mtime"]=stat(cName)[ST_MTIME] 192 times=sol.getTimes() 193 try: 194 data["first"]=times[0] 195 except IndexError: 196 data["first"]="None" 197 try: 198 data["last"]=times[-1] 199 except IndexError: 200 data["last"]="None" 201 data["nrSteps"]=len(times) 202 data["procs"]=sol.nrProcs() 203 data["pFirst"]=-1 204 data["pLast"]=-1 205 data["nrParallel"]=-1 206 if self.opts.parallel: 207 pTimes=sol.getParallelTimes() 208 data["nrParallel"]=len(pTimes) 209 if len(pTimes)>0: 210 data["pFirst"]=pTimes[0] 211 data["pLast"]=pTimes[-1] 212 data["name"]=cName 213 data["diskusage"]=-1 214 if self.opts.diskusage: 215 data["diskusage"]=diskUsage(cName) 216 totalDiskusage+=data["diskusage"] 217 if self.opts.parallel: 218 for f in listdir(cName): 219 if re.compile("processor[0-9]+").match(f): 220 data["mtime"]=max(stat(path.join(cName,f))[ST_MTIME],data["mtime"]) 221 222 if self.opts.state: 223 try: 224 data["nowTime"]=float(self.readState(sol,"CurrentTime")) 225 except ValueError: 226 data["nowTime"]=None 227 228 try: 229 data["lastOutput"]=time.mktime(time.strptime(self.readState(sol,"LastOutputSeen"))) 230 except ValueError: 231 data["lastOutput"]="nix" 232 233 data["state"]=self.readState(sol,"TheState") 234 235 if self.opts.state or self.opts.estimateEndTime: 236 try: 237 data["startedAt"]=time.mktime(time.strptime(self.readState(sol,"StartedAt"))) 238 except ValueError: 239 data["startedAt"]="nix" 240 241 if self.opts.startEndTime or self.opts.estimateEndTime: 242 try: 243 ctrlDict=ParsedParameterFile(sol.controlDict(),doMacroExpansion=True) 244 except PyFoamParserError: 245 # Didn't work with Macro expansion. Let's try without 246 try: 247 ctrlDict=ParsedParameterFile(sol.controlDict()) 248 except PyFoamParserError: 249 ctrlDict=None 250 if ctrlDict: 251 data["startTime"]=ctrlDict["startTime"] 252 data["endTime"]=ctrlDict["endTime"] 253 else: 254 data["startTime"]=None 255 data["endTime"]=None 256 257 if self.opts.estimateEndTime: 258 data["endTimeEstimate"]=None 259 if self.readState(sol,"TheState")=="Running": 260 gone=time.time()-data["startedAt"] 261 try: 262 current=float(self.readState(sol,"CurrentTime")) 263 frac=(current-data["startTime"])/(data["endTime"]-data["startTime"]) 264 except ValueError: 265 frac=0 266 if frac>0: 267 data["endTimeEstimate"]=data["startedAt"]+gone/frac 268 269 if len(customData)>0: 270 fn=None 271 pickleFile=None 272 if useSolverInData: 273 data["solver"]="none found" 274 # try to find the oldest pickled file 275 for f in ["pickledData","pickledUnfinishedData","pickledStartData"]: 276 dirAndTime=[] 277 for g in glob(path.join(cName,"*.analyzed")): 278 pName=path.join(g,f) 279 base=path.basename(g) 280 if base.find("PyFoamRunner.")==0: 281 solverName=base[len("PyFoamRunner."):-len(".analyzed")] 282 else: 283 solverName=None 284 if path.exists(pName): 285 dirAndTime.append((path.getmtime(pName),solverName,pName)) 286 dirAndTime.sort(key=lambda x:x[0]) 287 if len(dirAndTime)>0: 288 data["solver"]=dirAndTime[-1][1] 289 pickleFile=dirAndTime[-1][2] 290 break 291 292 solverName=data["solver"] 293 else: 294 solverName=self.opts.solverNameForCustom 295 296 if pickleFile: 297 fn=pickleFile 298 else: 299 for f in ["pickledData","pickledUnfinishedData","pickledStartData"]: 300 fp=path.join(cName,"PyFoamRunner."+solverName+".analyzed",f) 301 if path.exists(fp): 302 fn=fp 303 break 304 if fn: 305 raw=pickle.Unpickler(open(fn)).load() 306 for n,spec in customData: 307 dt=raw 308 for k in spec: 309 try: 310 dt=dt[k] 311 except KeyError: 312 dt="No key '"+k+"'" 313 break 314 if isinstance(dt,string_types): 315 break 316 data[n]=dt 317 else: 318 for n,spec in customData: 319 data[n]="no file" 320 321 cData.append(data) 322 except OSError: 323 print_(cName,"is unreadable") 324 325 if self.opts.progress: 326 print_("Sorting data") 327 328 329 cData.sort(key=lambda x:x[self.opts.sort],reverse=self.opts.reverse) 330 331 if len(cData)==0: 332 print_("No cases found") 333 return 334 335 if self.opts.dump: 336 print_(cData) 337 return 338 339 lens={} 340 for k in list(cData[0].keys()): 341 lens[k]=len(k) 342 for c in cData: 343 for k in ["mtime","lastOutput","startedAt","endTimeEstimate"]: 344 try: 345 if c[k]!=None: 346 if self.opts.relativeTime: 347 c[k]=datetime.timedelta(seconds=long(time.time()-c[k])) 348 else: 349 c[k]=time.asctime(time.localtime(c[k])) 350 except KeyError: 351 pass 352 except TypeError: 353 c[k]=None 354 355 try: 356 c["diskusage"]=humanReadableSize(c["diskusage"]) 357 except KeyError: 358 pass 359 360 for k,v in iteritems(c): 361 lens[k]=max(lens[k],len(str(v))) 362 363 format="" 364 spec=["mtime"," | ","first"," - ","last"," (","nrSteps",") "] 365 if self.opts.parallel: 366 spec+=["| ","procs"," : ","pFirst"," - ","pLast"," (","nrParallel",") | "] 367 if self.opts.diskusage: 368 spec+=["diskusage"," | "] 369 if self.hasState: 370 spec+=["nowTime"," s ","state"," | "] 371 if self.opts.advancedState: 372 spec+=["lastOutput"," | ","startedAt"," | "] 373 if self.opts.estimateEndTime: 374 if not self.opts.advancedState: 375 spec+=["startedAt"," | "] 376 spec+=["endTimeEstimate"," | "] 377 if self.opts.startEndTime: 378 spec+=["startTime"," | ","endTime"," | "] 379 380 if useSolverInData: 381 spec+=["solver"," | "] 382 for n,s in customData: 383 spec+=[n," | "] 384 385 spec+=["name"] 386 387 for i,l in enumerate(spec): 388 if not l in list(cData[0].keys()): 389 format+=l 390 else: 391 if i<len(spec)-1: 392 format+="%%(%s)%ds" % (l,lens[l]) 393 else: 394 format+="%%(%s)s" % (l) 395 396 if self.opts.progress: 397 print_("Printing\n\n") 398 399 header=format % dict(list(zip(list(cData[0].keys()),list(cData[0].keys())))) 400 print_(header) 401 print_("-"*len(header)) 402 403 for d in cData: 404 for k in list(d.keys()): 405 d[k]=str(d[k]) 406 print_(format % d) 407 408 if self.opts.diskusage: 409 print_("Total disk-usage:",humanReadableSize(totalDiskusage))
410 411 412 # Should work with Python3 and Python2 413