Package PyFoam :: Package RunDictionary :: Module SolutionDirectory
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.RunDictionary.SolutionDirectory

  1  #  ICE Revision: $Id: SolutionDirectory.py 9441 2008-09-22 20:51:21Z bgschaid $  
  2  """Working with a solution directory""" 
  3   
  4  from PyFoam.Basics.Utilities import Utilities 
  5  from PyFoam.Basics.BasicFile import BasicFile 
  6  from TimeDirectory import TimeDirectory 
  7   
  8  from os import listdir,path,mkdir,symlink,stat 
  9  from stat import ST_CTIME 
 10  import tarfile,fnmatch 
 11  import re 
 12   
13 -class SolutionDirectory(Utilities):
14 """Represents a solution directory 15 16 In the solution directory subdirectories whose names are numbers 17 are assumed to be solutions for a specific time-step 18 19 A sub-directory (called the Archive) is created to which solution 20 data is copied""" 21
22 - def __init__(self,name,archive="ArchiveDir",paraviewLink=True,region=None):
23 """@param name: Name of the solution directory 24 @param archive: name of the directory where the lastToArchive-method 25 should copy files, if None no archive is created 26 @param paraviewLink: Create a symbolic link controlDict.foam for paraview 27 @param region: Mesh region for multi-region cases""" 28 29 self.name=path.abspath(name) 30 self.archive=None 31 if archive!=None: 32 self.archive=path.join(name,archive) 33 if not path.exists(self.archive): 34 mkdir(self.archive) 35 36 self.region=region 37 self.backups=[] 38 39 self.lastReread=0L 40 self.reread() 41 42 self.essential=[self.systemDir(),self.constantDir(),self.initialDir()] 43 44 if paraviewLink and not path.exists(self.controlDict()+".foam"): 45 symlink(path.basename(self.controlDict()),self.controlDict()+".foam")
46
47 - def __len__(self):
48 self.reread() 49 return len(self.times)
50
51 - def __contains__(self,item):
52 self.reread() 53 54 if self.timeName(item)!=None: 55 return True 56 else: 57 return False
58
59 - def __getitem__(self,key):
60 self.reread() 61 62 ind=self.timeName(key) 63 if ind==None: 64 raise KeyError(key) 65 else: 66 return TimeDirectory(self.name,ind,region=self.region)
67
68 - def __setitem__(self,key,value):
69 self.reread() 70 if type(key)!=str: 71 raise TypeError(type(key),"of",key,"is not 'str'") 72 73 if type(value)!=TimeDirectory: 74 raise TypeError(type(value),"is not TimeDirectory") 75 76 dest=TimeDirectory(self.name,key,create=True,region=self.region) 77 dest.copy(value) 78 79 self.reread(force=True)
80
81 - def __delitem__(self,key):
82 self.reread() 83 nm=self.timeName(key) 84 if nm==None: 85 raise KeyError(key) 86 87 self.execute("rm -rf "+path.join(self.name,nm)) 88 89 self.reread(force=True)
90
91 - def __iter__(self):
92 self.reread() 93 for key in self.times: 94 yield TimeDirectory(self.name,key,region=self.region)
95
96 - def timeName(self,item):
97 """Finds the name of a directory that corresponds with the given parameter 98 @param item: the time that should be found""" 99 100 if type(item)==int: 101 return self.times[item] 102 else: 103 ind=self.timeIndex(item) 104 if ind==None: 105 return None 106 else: 107 return self.times[ind]
108
109 - def timeIndex(self,item,minTime=False):
110 """Finds the index of a directory that corresponds with the given parameter 111 @param item: the time that should be found 112 @param minTime: search for the time with the minimal difference. 113 Otherwise an exact match will be searched""" 114 self.reread() 115 116 time=float(item) 117 result=None 118 119 if minTime: 120 result=0 121 for i in range(1,len(self.times)): 122 if abs(float(self.times[result])-time)>abs(float(self.times[i])-time): 123 result=i 124 else: 125 for i in range(len(self.times)): 126 t=self.times[i] 127 if abs(float(t)-time)<1e-6: 128 if result==None: 129 result=i 130 elif abs(float(t)-time)<abs(float(self.times[result])-time): 131 result=i 132 133 return result
134
135 - def isValid(self):
136 """Checks whether this is a valid case directory by looking for 137 the system- and constant-directories and the controlDict-file""" 138 if not path.exists(self.systemDir()): 139 return False 140 elif not path.isdir(self.systemDir()): 141 return False 142 elif not path.exists(self.constantDir()): 143 return False 144 elif not path.isdir(self.constantDir()): 145 return False 146 elif not path.exists(self.controlDict()): 147 return False 148 else: 149 return True
150
151 - def addToClone(self,name):
152 """add directory to the list that is needed to clone this case 153 @param name: name of the subdirectory (the case directory is prepended)""" 154 self.essential.append(path.join(self.name,name))
155
156 - def cloneCase(self,name,svnRemove=True):
157 """create a clone of this case directory. Remove the target directory, if it already exists 158 159 @param name: Name of the new case directory 160 @param svnRemove: Look for .svn-directories and remove them 161 @rtype: L{SolutionDirectory} or correct subclass 162 @return: The target directory""" 163 164 if path.exists(name): 165 self.execute("rm -r "+name) 166 mkdir(name) 167 for d in self.essential: 168 self.execute("cp -r "+d+" "+name) 169 170 if svnRemove: 171 self.execute("find "+name+" -name .svn -exec rm -rf {} \\; -prune") 172 173 return self.__class__(name,archive=self.archive)
174
175 - def packCase(self,tarname,last=False,exclude=[],additional=[]):
176 """Packs all the important files into a compressed tarfile. 177 Uses the essential-list and excludes the .svn-directories. 178 Also excludes files ending with ~ 179 @param tarname: the name of the tar-file 180 @param last: add the last directory to the list of directories to be added 181 @param exclude: List with additional glob filename-patterns to be excluded 182 @param additional: List with additional glob filename-patterns 183 that are to be added""" 184 185 ex=["*~",".svn"]+exclude 186 members=self.essential[:] 187 if last: 188 if self.getLast()!=self.first: 189 members.append(self.latestDir()) 190 for p in additional: 191 for f in listdir(self.name): 192 if (f not in members) and fnmatch.fnmatch(f,p): 193 members.append(path.join(self.name,f)) 194 195 tar=tarfile.open(tarname,"w:gz") 196 197 for m in members: 198 self.addToTar(tar,m,exclude=ex) 199 200 tar.close()
201
202 - def addToTar(self,tar,name,exclude=[]):
203 """The workhorse for the packCase-method""" 204 205 for e in exclude: 206 if fnmatch.fnmatch(path.basename(name),e): 207 return 208 209 if path.isdir(name): 210 for m in listdir(name): 211 self.addToTar(tar,path.join(name,m),exclude=exclude) 212 else: 213 tar.add(name)
214
215 - def reread(self,force=False):
216 """Rescan the directory for the time directories""" 217 218 if not force and stat(self.name)[ST_CTIME]<=self.lastReread: 219 return 220 221 self.times=[] 222 self.first=None 223 self.last=None 224 self.procDirs=0 225 226 for f in listdir(self.name): 227 try: 228 val=float(f) 229 self.times.append(f) 230 if self.first==None: 231 self.first=f 232 else: 233 if float(f)<float(self.first): 234 self.first=f 235 if self.last==None: 236 self.last=f 237 else: 238 if float(f)>float(self.last): 239 self.last=f 240 241 except ValueError: 242 if re.compile("processor[0-9]+").match(f): 243 self.procDirs+=1 244 245 self.lastReread=stat(self.name)[ST_CTIME] 246 247 self.times.sort(self.sorttimes)
248
249 - def processorDirs(self):
250 """List with the processor directories""" 251 dirs=[] 252 for f in listdir(self.name): 253 if re.compile("processor[0-9]+").match(f): 254 dirs.append(f) 255 256 return dirs
257
258 - def nrProcs(self):
259 """The number of directories with processor-data""" 260 self.reread() 261 return self.procDirs
262
263 - def sorttimes(self,x,y):
264 """Sort function for the solution files""" 265 if(float(x)==float(y)): 266 return 0 267 elif float(x)<float(y): 268 return -1 269 else: 270 return 1
271
272 - def getTimes(self):
273 """ @return: List of all the available times""" 274 self.reread() 275 return self.times
276
277 - def addBackup(self,pth):
278 """add file to list of files that are to be copied to the 279 archive""" 280 self.backups.append(path.join(self.name,pth))
281
282 - def getLast(self):
283 """@return: the last time for which a solution exists 284 @rtype: str""" 285 self.reread() 286 return self.last
287
288 - def lastToArchive(self,name):
289 """copy the last solution (plus the backup-files to the 290 archive) 291 292 @param name: name of the sub-directory in the archive""" 293 if self.archive==None: 294 print "Warning: nor Archive-directory" 295 return 296 297 self.reread() 298 fname=path.join(self.archive,name) 299 if path.exists(fname): 300 self.execute("rm -r "+fname) 301 mkdir(fname) 302 self.execute("cp -r "+path.join(self.name,self.last)+" "+fname) 303 for f in self.backups: 304 self.execute("cp -r "+f+" "+fname)
305
306 - def clearResults(self,after=None,removeProcs=False,keepLast=False,vtk=True):
307 """remove all time-directories after a certain time. If not time ist 308 set the initial time is used 309 @param after: time after which directories ar to be removed 310 @param removeProcs: if True the processorX-directories are removed. 311 Otherwise the timesteps after last are removed from the 312 processor-directories 313 @param keepLast: Keep the data from the last timestep 314 @param vtk: Remove the VTK-directory if it exists""" 315 316 self.reread() 317 318 last=self.getLast() 319 320 if after==None: 321 time=float(self.first) 322 else: 323 time=float(after) 324 325 for f in self.times: 326 if float(f)>time and not (keepLast and f==last): 327 self.execute("rm -r "+path.join(self.name,f)) 328 329 if path.exists(path.join(self.name,"VTK")) and vtk: 330 self.execute("rm -r "+path.join(self.name,"VTK")) 331 332 if self.nrProcs(): 333 for f in listdir(self.name): 334 if re.compile("processor[0-9]+").match(f): 335 if removeProcs: 336 self.execute("rm -r "+path.join(self.name,f)) 337 else: 338 pDir=path.join(self.name,f) 339 for t in listdir(pDir): 340 try: 341 val=float(t) 342 if val>time: 343 self.execute("rm -r "+path.join(pDir,t)) 344 except ValueError: 345 pass
346
347 - def clearPattern(self,glob):
348 """Clear all files that fit a certain shell (glob) pattern 349 @param glob: the pattern which the files are going to fit""" 350 351 self.execute("rm -rf "+path.join(self.name,glob))
352
353 - def clearOther(self,pyfoam=True):
354 """Remove additional directories 355 @param pyfoam: rremove all directories typically created by PyFoam""" 356 357 if pyfoam: 358 self.clearPattern("PyFoam.?*") 359 self.clearPattern("*?.analyzed")
360
361 - def clear(self,after=None,processor=True,pyfoam=True,keepLast=False):
362 """One-stop-shop to remove data 363 @param after: time after which directories ar to be removed 364 @param processor: remove the processorXX directories 365 @param pyfoam: rremove all directories typically created by PyFoam 366 @param keepLast: Keep the last time-step""" 367 self.clearResults(after=after,removeProcs=processor,keepLast=keepLast) 368 self.clearOther(pyfoam=pyfoam)
369
370 - def initialDir(self):
371 """@return: the name of the first time-directory (==initial 372 conditions 373 @rtype: str""" 374 self.reread() 375 376 if self.first: 377 return path.join(self.name,self.first) 378 else: 379 return None
380
381 - def latestDir(self):
382 """@param region: Specify the region for cases with more than 1 mesh 383 @return: the name of the first last-directory (==simulation 384 results) 385 @rtype: str""" 386 self.reread() 387 388 last=self.getLast() 389 if last: 390 return path.join(self.name,last) 391 else: 392 return None
393
394 - def constantDir(self,region=None,processor=None):
395 """@param region: Specify the region for cases with more than 1 mesh 396 @param processor: name of the processor directory 397 @return: the name of the C{constant}-directory 398 @rtype: str""" 399 pre=self.name 400 if processor!=None: 401 pre=path.join(pre,processor) 402 403 if region==None and self.region!=None: 404 region=self.region 405 if region: 406 return path.join(pre,"constant",region) 407 else: 408 return path.join(pre,"constant")
409
410 - def systemDir(self,region=None):
411 """@param region: Specify the region for cases with more than 1 mesh 412 @return: the name of the C{system}-directory 413 @rtype: str""" 414 if region==None and self.region!=None: 415 region=self.region 416 if region: 417 return path.join(self.name,"system",region) 418 else: 419 return path.join(self.name,"system")
420
421 - def controlDict(self):
422 """@param region: Specify the region for cases with more than 1 mesh 423 @return: the name of the C{controlDict} 424 @rtype: str""" 425 return path.join(self.systemDir(),"controlDict")
426
427 - def polyMeshDir(self,region=None,time="constant",processor=None):
428 """@param region: Specify the region for cases with more than 1 mesh 429 @return: the name of the C{polyMesh} 430 @param time: Time for which the mesh should be looked at 431 @param processor: Name of the processor directory for decomposed cases 432 @rtype: str""" 433 if region==None and self.region!=None: 434 region=self.region 435 return path.join(self.constantDir(region=region,processor=processor),"polyMesh")
436
437 - def boundaryDict(self,region=None,time="constant",processor=None):
438 """@param region: Specify the region for cases with more than 1 mesh 439 @return: name of the C{boundary}-file 440 @rtype: str""" 441 if region==None and self.region!=None: 442 region=self.region 443 return path.join(self.polyMeshDir(region=region,time=time,processor=processor),"boundary")
444
445 - def blockMesh(self,region=None):
446 """@param region: Specify the region for cases with more than 1 mesh 447 @return: the name of the C{blockMeshDict} if it exists. Returns 448 an empty string if it doesn't 449 @rtype: str""" 450 if region==None and self.region!=None: 451 region=self.region 452 p=path.join(self.polyMeshDir(region=region),"blockMeshDict") 453 if path.exists(p): 454 return p 455 else: 456 return ""
457
458 - def makeFile(self,name):
459 """create a file in the solution directory and return a 460 corresponding BasicFile-object 461 462 @param name: Name of the file 463 @rtype: L{BasicFile}""" 464 return BasicFile(path.join(self.name,name))
465
466 - def getRegions(self):
467 """Gets a list of all the available mesh regions by checking all 468 directories in constant and using all those that have a polyMesh-subdirectory""" 469 lst=[] 470 for d in self.listDirectory(self.constantDir()): 471 if path.isdir(path.join(self.constantDir(),d)): 472 if path.exists(self.polyMeshDir(region=d)): 473 lst.append(d) 474 lst.sort() 475 return lst
476
477 -class ChemkinSolutionDirectory(SolutionDirectory):
478 """Solution directory with a directory for the Chemkin-files""" 479 480 chemkinName = "chemkin" 481
482 - def __init__(self,name,archive="ArchiveDir"):
483 SolutionDirectory.__init__(self,name,archive=archive) 484 485 self.addToClone(self.chemkinName)
486
487 - def chemkinDir(self):
488 """@rtype: str 489 @return: The directory with the Chemkin-Files""" 490 491 return path.join(self.name,self.chemkinName)
492