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

Source Code for Module PyFoam.RunDictionary.SolutionDirectory

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/RunDictionary/SolutionDirectory.py 8448 2013-09-24T17:55:25.403256Z bgschaid  $ 
  2  """Working with a solution directory""" 
  3   
  4  from PyFoam.Basics.Utilities import Utilities 
  5  from PyFoam.Basics.BasicFile import BasicFile 
  6  from PyFoam.Error import warning,error 
  7  from PyFoam import configuration as conf 
  8   
  9  from PyFoam.RunDictionary.TimeDirectory import TimeDirectory 
 10  from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,WriteParameterFile 
 11   
 12  from PyFoam.Basics.DataStructures import DictProxy 
 13   
 14  from PyFoam.ThirdParty.six import print_ 
 15   
 16  from os import listdir,path,mkdir,stat,environ 
 17  from platform import uname 
 18  from time import asctime 
 19  from stat import ST_CTIME 
 20  import tarfile,fnmatch,glob 
 21  import re,os 
 22   
 23  try: 
 24      from os import getlogin 
 25  except ImportError: 
 26      try: 
 27          import PyFoam.ThirdParty.winhacks 
 28      except ImportError: 
 29          print_("Unable to import the getlogin function.") 
 30          import sys 
 31          sys.exit(-1) 
 32   
33 -class SolutionDirectory(Utilities):
34 """Represents a solution directory 35 36 In the solution directory subdirectories whose names are numbers 37 are assumed to be solutions for a specific time-step 38 39 A sub-directory (called the Archive) is created to which solution 40 data is copied""" 41
42 - def __init__(self, 43 name, 44 archive="ArchiveDir", 45 paraviewLink=True, 46 parallel=False, 47 addLocalConfig=False, 48 tolerant=False, 49 region=None):
50 """@param name: Name of the solution directory 51 @param archive: name of the directory where the lastToArchive-method 52 should copy files, if None no archive is created 53 @param paraviewLink: Create a symbolic link controlDict.foam for paraview 54 @param tolerant: do not fail for minor inconsistencies 55 @param parallel: use the first processor-subdirectory for the authorative information 56 @param region: Mesh region for multi-region cases""" 57 58 self.name=path.abspath(name) 59 self.archive=None 60 if archive!=None: 61 self.archive=path.join(name,archive) 62 if not path.exists(self.archive): 63 mkdir(self.archive) 64 65 self.region=region 66 self.backups=[] 67 68 self.parallel=parallel 69 self.tolerant=tolerant 70 71 self.lastReread=0 72 self.reread() 73 74 self.dirPrefix='' 75 if self.processorDirs() and parallel: 76 self.dirPrefix = self.processorDirs()[0] 77 78 self.essential=set([self.systemDir(), 79 self.constantDir(), 80 self.initialDir()]) 81 82 # PyFoam-specific 83 self.addToClone("PyFoamHistory") 84 self.addToClone("customRegexp") 85 self.addToClone("LocalConfigPyFoam") 86 87 # this usually comes with the tutorials 88 self.addToClone("Allclean") 89 self.addToClone("Allrun") 90 # self.addToClone("0.org") 91 92 emptyFoamFile=path.join(self.name,path.basename(self.name)+".foam") 93 if paraviewLink and not path.exists(emptyFoamFile): 94 dummy=open(emptyFoamFile,"w") # equivalent to touch 95 96 if addLocalConfig: 97 self.addLocalConfig()
98
99 - def setToParallel(self):
100 """Use the parallel times instead of the serial. 101 102 Used to reset the behaviour after it has been set by the constructor""" 103 if self.parallel: 104 warning(self.name,"is already in parallel mode") 105 else: 106 self.parallel=True 107 if self.processorDirs(): 108 self.dirPrefix = self.processorDirs()[0] 109 self.reread(force=True)
110
111 - def addLocalConfig(self):
112 """Add the local configuration file of the case to the configuration""" 113 fName=path.join(self.name,"LocalConfigPyFoam") 114 if path.exists(fName): 115 conf().addFile(fName)
116
117 - def __len__(self):
118 self.reread() 119 return len(self.times)
120
121 - def __contains__(self,item):
122 self.reread() 123 124 if self.timeName(item)!=None: 125 return True 126 else: 127 return False
128
129 - def __getitem__(self,key):
130 self.reread() 131 132 ind=self.timeName(key) 133 if ind==None: 134 raise KeyError(key) 135 else: 136 return TimeDirectory(self.name, self.fullPath(ind), region=self.region)
137
138 - def __setitem__(self,key,value):
139 self.reread() 140 if type(key)!=str: 141 raise TypeError(type(key),"of",key,"is not 'str'") 142 143 if type(value)!=TimeDirectory: 144 raise TypeError(type(value),"is not TimeDirectory") 145 146 dest=TimeDirectory(self.name, self.fullPath(key), create=True,region=self.region) 147 dest.copy(value) 148 149 self.reread(force=True)
150
151 - def __delitem__(self,key):
152 self.reread() 153 nm=self.timeName(key) 154 if nm==None: 155 raise KeyError(key) 156 157 self.rmtree(path.join(self.name, self.fullPath(nm)),ignore_errors=True) 158 159 self.reread(force=True)
160
161 - def __iter__(self):
162 self.reread() 163 for key in self.times: 164 yield TimeDirectory(self.name, 165 self.fullPath(key), 166 region=self.region, 167 tolerant=self.tolerant)
168
169 - def timeName(self,item,minTime=False):
170 """Finds the name of a directory that corresponds with the given parameter 171 @param item: the time that should be found 172 @param minTime: search for the time with the minimal difference. 173 Otherwise an exact match will be searched""" 174 175 if type(item)==int: 176 return self.times[item] 177 else: 178 ind=self.timeIndex(item,minTime) 179 if ind==None: 180 return None 181 else: 182 return self.times[ind]
183
184 - def timeIndex(self,item,minTime=False):
185 """Finds the index of a directory that corresponds with the given parameter 186 @param item: the time that should be found 187 @param minTime: search for the time with the minimal difference. 188 Otherwise an exact match will be searched""" 189 self.reread() 190 191 time=float(item) 192 result=None 193 194 if minTime: 195 result=0 196 for i in range(1,len(self.times)): 197 if abs(float(self.times[result])-time)>abs(float(self.times[i])-time): 198 result=i 199 else: 200 for i in range(len(self.times)): 201 t=self.times[i] 202 if abs(float(t)-time)<1e-6: 203 if result==None: 204 result=i 205 elif abs(float(t)-time)<abs(float(self.times[result])-time): 206 result=i 207 208 return result
209
210 - def fullPath(self,time):
211 if self.dirPrefix: 212 return path.join(self.dirPrefix, time) 213 return time
214
215 - def isValid(self):
216 """Checks whether this is a valid case directory by looking for 217 the system- and constant-directories and the controlDict-file""" 218 219 return len(self.missingFiles())==0
220
221 - def missingFiles(self):
222 """Return a list of all the missing files and directories that 223 are needed for a valid case""" 224 missing=[] 225 if not path.exists(self.systemDir()): 226 missing.append(self.systemDir()) 227 elif not path.isdir(self.systemDir()): 228 missing.append(self.systemDir()) 229 if not path.exists(self.constantDir()): 230 missing.append(self.constantDir()) 231 elif not path.isdir(self.constantDir()): 232 missing.append(self.constantDir()) 233 if not path.exists(self.controlDict()): 234 missing.append(self.controlDict()) 235 236 return missing
237
238 - def addToClone(self,name):
239 """add directory to the list that is needed to clone this case 240 @param name: name of the subdirectory (the case directory is prepended)""" 241 if path.exists(path.join(self.name,name)): 242 self.essential.add(path.join(self.name,name)) 243 elif self.parallel: 244 if path.exists(path.join(self.name,"processor0",name)): 245 self.essential.add(path.join(self.name,name))
246
247 - def cloneCase(self,name,svnRemove=True,followSymlinks=False):
248 """create a clone of this case directory. Remove the target directory, if it already exists 249 250 @param name: Name of the new case directory 251 @param svnRemove: Look for .svn-directories and remove them 252 @param followSymlinks: Follow symbolic links instead of just copying them 253 @rtype: L{SolutionDirectory} or correct subclass 254 @return: The target directory""" 255 256 additional=eval(conf().get("Cloning","addItem")) 257 for a in additional: 258 self.addToClone(a) 259 260 cpOptions="-R" 261 if followSymlinks: 262 cpOptions+=" -L" 263 264 if path.exists(name): 265 self.rmtree(name) 266 mkdir(name) 267 if self.parallel: 268 for i in range(self.nrProcs()): 269 mkdir(path.join(name,"processor%d" % i)) 270 271 for d in self.essential: 272 if d!=None: 273 if self.parallel: 274 pth,fl=path.split(d) 275 if path.exists(path.join(pth,"processor0",fl)): 276 for i in range(self.nrProcs()): 277 self.copytree(path.join(pth,"processor%d" % i,fl), 278 path.join(name,"processor%d" % i), 279 symlinks=not followSymlinks) 280 281 if path.exists(d): 282 self.copytree(d,name,symlinks=not followSymlinks) 283 284 if svnRemove: 285 self.execute("find "+name+" -name .svn -exec rm -rf {} \\; -prune") 286 287 return self.__class__(name,archive=self.archive)
288
289 - def symlinkCase(self, 290 name, 291 followSymlinks=False, 292 maxLevel=1, 293 relPath=False):
294 """create a clone of this case directory by creating a 295 directory with symbolic links 296 297 @param name: Name of the new case directory 298 @param maxLevel: Maximum level down to which directories are created instead of symbolically linked 299 @param followSymlinks: Follow symbolic links instead of just copying them 300 @param relPath: the created symbolic links are relative (instead of absolute) 301 @rtype: L{SolutionDirectory} or correct subclass 302 @return: The target directory 303 """ 304 here=path.abspath(self.name) 305 polyDirs=[path.relpath(p,here) for p in self.find("polyMesh*",here)] 306 307 additional=eval(conf().get("Cloning","addItem")) 308 for a in additional: 309 self.addToClone(a) 310 311 if path.exists(name): 312 self.rmtree(name) 313 mkdir(name) 314 toProcess=[] 315 for d in self.essential: 316 if d!=None: 317 if self.parallel: 318 pth,fl=path.split(d) 319 if path.exists(path.join(pth,"processor0",fl)): 320 for i in range(self.nrProcs()): 321 toProcess.append("processor%d" % i) 322 if path.exists(d): 323 toProcess.append(path.relpath(d,here)) 324 325 maxLevel=max(0,maxLevel) 326 327 self.__symlinkDir(src=here, 328 dest=path.abspath(name), 329 toProcess=toProcess, 330 maxLevel=maxLevel, 331 relPath=relPath, 332 polyDirs=polyDirs, 333 symlinks=not followSymlinks) 334 335 return self.__class__(name,archive=self.archive)
336
337 - def __symlinkDir(self,src,dest,toProcess,maxLevel,relPath,polyDirs,symlinks):
338 for f in toProcess: 339 there=path.join(src,f) 340 here=path.join(dest,f) 341 if path.islink(there) and not symlinks: 342 there=path.realpath(there) 343 344 doSymlink=False 345 done=False 346 347 if not path.isdir(there): 348 doSymlink=True 349 if path.basename(src)=="polyMesh": 350 if f not in ["blockMeshDict","blockMeshDict.gz"]: 351 doSymlink=False 352 else: 353 poly=[p for p in polyDirs if p.split(path.sep)[0]==f] 354 if maxLevel>0 or len(poly)>0: 355 done=True 356 mkdir(here) 357 self.__symlinkDir(src=there,dest=here, 358 toProcess=[p for p in os.listdir(there) if p[0]!='.'], 359 maxLevel=max(0,maxLevel-1), 360 relPath=relPath, 361 polyDirs=[path.join(*p.split(path.sep)[1:]) for p in poly if len(p.split(path.sep))>1], 362 symlinks=symlinks) 363 else: 364 doSymlink=True 365 366 if not done: 367 if doSymlink: 368 if relPath: 369 linkTo=path.relpath(there,dest) 370 else: 371 linkTo=path.abspath(there) 372 os.symlink(linkTo,here) 373 else: 374 self.copytree(there,here,symlinks=symlinks)
375
376 - def packCase(self,tarname,last=False,exclude=[],additional=[],base=None):
377 """Packs all the important files into a compressed tarfile. 378 Uses the essential-list and excludes the .svn-directories. 379 Also excludes files ending with ~ 380 @param tarname: the name of the tar-file 381 @param last: add the last directory to the list of directories to be added 382 @param exclude: List with additional glob filename-patterns to be excluded 383 @param additional: List with additional glob filename-patterns 384 that are to be added 385 @param base: Different name that is to be used as the baseName for the case inside the tar""" 386 387 ex=["*~",".svn"]+exclude 388 members=list(self.essential) 389 if last: 390 if self.getLast()!=self.first: 391 members.append(self.latestDir()) 392 for p in additional: 393 for f in listdir(self.name): 394 if (f not in members) and fnmatch.fnmatch(f,p): 395 members.append(path.join(self.name,f)) 396 397 tar=tarfile.open(tarname,"w:gz") 398 399 for m in members: 400 self.addToTar(tar,m,exclude=ex,base=base) 401 402 additional=eval(conf().get("Cloning","addItem")) 403 for a in additional: 404 self.addToTar(tar, 405 path.join(self.name,a), 406 exclude=ex, 407 base=base) 408 409 tar.close()
410
411 - def addToTar(self,tar,name,exclude=[],base=None):
412 """The workhorse for the packCase-method""" 413 414 if base==None: 415 base=path.basename(self.name) 416 417 for e in exclude: 418 if fnmatch.fnmatch(path.basename(name),e): 419 return 420 421 if path.isdir(name): 422 for m in listdir(name): 423 self.addToTar(tar,path.join(name,m),exclude=exclude,base=base) 424 else: 425 arcname=path.join(base,name[len(self.name)+1:]) 426 if path.islink(name): 427 # if the symbolic link points to a file in the case keep it 428 # otherwise replace with the real file 429 lPath=path.os.readlink(name) 430 if not path.isabs(lPath): 431 rPath=path.realpath(name) 432 common=path.commonprefix([path.abspath(rPath), 433 path.abspath(base)]) 434 # if the path is shorter than the base it must be outside the case 435 if len(common)<len(path.abspath(base)): 436 name=path.abspath(rPath) 437 else: 438 # use the abolute path 439 name=lPath 440 tar.add(name,arcname=arcname)
441
442 - def getParallelTimes(self):
443 """Get a list of the times in the processor0-directory""" 444 result=[] 445 446 proc0=path.join(self.name,"processor0") 447 if path.exists(proc0): 448 for f in listdir(proc0): 449 try: 450 val=float(f) 451 result.append(f) 452 except ValueError: 453 pass 454 result.sort(key=float) 455 return result
456
457 - def reread(self,force=False):
458 """Rescan the directory for the time directories""" 459 460 if not force and stat(self.name)[ST_CTIME]<=self.lastReread: 461 return 462 463 self.times=[] 464 self.first=None 465 self.last=None 466 procDirs = self.processorDirs() 467 self.procNr=len(procDirs) 468 469 if procDirs and self.parallel: 470 timesDir = path.join(self.name, procDirs[0]) 471 else: 472 timesDir = self.name 473 474 for f in listdir(timesDir): 475 try: 476 val=float(f) 477 self.times.append(f) 478 except ValueError: 479 pass 480 481 self.lastReread=stat(self.name)[ST_CTIME] 482 483 self.times.sort(key=float) 484 if self.times: 485 self.first = self.times[0] 486 self.last = self.times[-1]
487
488 - def processorDirs(self):
489 """List with the processor directories""" 490 try: 491 return self.procDirs 492 except: 493 pass 494 self.procDirs=[] 495 for f in listdir(self.name): 496 if re.compile("processor[0-9]+").match(f): 497 self.procDirs.append(f) 498 499 return self.procDirs
500
501 - def nrProcs(self):
502 """The number of directories with processor-data""" 503 self.reread() 504 return self.procNr
505
506 - def getTimes(self):
507 """ @return: List of all the available times""" 508 self.reread() 509 return self.times
510
511 - def addBackup(self,pth):
512 """add file to list of files that are to be copied to the 513 archive""" 514 self.backups.append(path.join(self.name,pth))
515
516 - def getFirst(self):
517 """@return: the first time for which a solution exists 518 @rtype: str""" 519 self.reread() 520 return self.first
521
522 - def getLast(self):
523 """@return: the last time for which a solution exists 524 @rtype: str""" 525 self.reread() 526 return self.last
527
528 - def lastToArchive(self,name):
529 """copy the last solution (plus the backup-files to the 530 archive) 531 532 @param name: name of the sub-directory in the archive""" 533 if self.archive==None: 534 print_("Warning: nor Archive-directory") 535 return 536 537 self.reread() 538 fname=path.join(self.archive,name) 539 if path.exists(fname): 540 self.rmtree(fname) 541 mkdir(fname) 542 self.copytree(path.join(self.name,self.last),fname) 543 for f in self.backups: 544 self.copytree(f,fname)
545
546 - def clearResults(self, 547 after=None, 548 removeProcs=False, 549 keepLast=False, 550 vtk=True, 551 keepRegular=False, 552 keepParallel=False, 553 keepInterval=None, 554 functionObjectData=False, 555 additional=[]):
556 """remove all time-directories after a certain time. If not time ist 557 set the initial time is used 558 @param after: time after which directories ar to be removed 559 @param removeProcs: if True the processorX-directories are removed. 560 Otherwise the timesteps after last are removed from the 561 processor-directories 562 @param keepLast: Keep the data from the last timestep 563 @param keepInterval: if set: keep timesteps that are this far apart 564 @param vtk: Remove the VTK-directory if it exists 565 @param keepRegular: keep all the times (only remove processor and other stuff) 566 @param functionObjectData: tries do determine which data was written by function obejects and removes it 567 @param additional: List with glob-patterns that are removed too""" 568 569 self.reread() 570 571 last=self.getLast() 572 573 if after==None: 574 try: 575 time=float(self.first) 576 except TypeError: 577 warning("The first timestep in",self.name," is ",self.first,"not a number. Doing nothing") 578 return 579 else: 580 time=float(after) 581 582 lastKeptIndex=int(-1e5) 583 584 if keepInterval!=None: 585 if keepInterval<=0: 586 error("The keeping interval",keepInterval,"is smaller that 0") 587 588 if not keepRegular: 589 for f in self.times: 590 keep=False 591 if keepInterval!=None: 592 thisIndex=int((float(f)+1e-10)/keepInterval) 593 if thisIndex!=lastKeptIndex: 594 keep=True 595 if float(f)>time and not (keepLast and f==last) and not keep: 596 # print "Removing",path.join(self.name,f) 597 self.rmtree(path.join(self.name,f)) 598 elif keepInterval!=None: 599 lastKeptIndex=int((float(f)+1e-10)/keepInterval) 600 601 if path.exists(path.join(self.name,"VTK")) and vtk: 602 self.rmtree(path.join(self.name,"VTK")) 603 604 if self.nrProcs() and not keepParallel: 605 lastKeptIndex=int(-1e5) 606 for f in listdir(self.name): 607 if re.compile("processor[0-9]+").match(f): 608 if removeProcs: 609 self.rmtree(path.join(self.name,f)) 610 else: 611 pDir=path.join(self.name,f) 612 for t in listdir(pDir): 613 try: 614 keep=False 615 val=float(t) 616 if keepInterval!=None: 617 thisIndex=int((float(f)+1e-10)/keepInterval) 618 if thisIndex!=lastKeptIndex: 619 keep=True 620 if val>time and not (keepLast and f==last) and not keep: 621 self.rmtree(path.join(pDir,t)) 622 elif keepInterval!=None: 623 lastKeptIndex=int((float(f)+1e-10)/keepInterval) 624 except ValueError: 625 pass 626 627 if functionObjectData: 628 cd=ParsedParameterFile(self.controlDict()) 629 if "functions" in cd: 630 if type(cd["functions"]) in [DictProxy,dict]: 631 for f in cd["functions"]: 632 pth=path.join(self.name,f) 633 if path.exists(pth): 634 self.rmtree(pth) 635 else: 636 for f in cd["functions"][0::2]: 637 pth=path.join(self.name,f) 638 if path.exists(pth): 639 self.rmtree(pth) 640 641 additional+=eval(conf().get("Clearing","additionalpatterns")) 642 for a in additional: 643 self.clearPattern(a)
644
645 - def clearPattern(self,globPat):
646 """Clear all files that fit a certain shell (glob) pattern 647 @param glob: the pattern which the files are going to fit""" 648 649 for f in glob.glob(path.join(self.name,globPat)): 650 if path.isdir(f): 651 self.rmtree(f,ignore_errors=False) 652 else: 653 os.unlink(f)
654
655 - def clearOther(self, 656 pyfoam=True, 657 removeAnalyzed=False, 658 clearHistory=False):
659 """Remove additional directories 660 @param pyfoam: rremove all directories typically created by PyFoam""" 661 662 if pyfoam: 663 self.clearPattern("PyFoam.?*") 664 if removeAnalyzed: 665 self.clearPattern("*?.analyzed") 666 if clearHistory: 667 self.clearPattern("PyFoamHistory")
668
669 - def clear(self, 670 after=None, 671 processor=True, 672 pyfoam=True, 673 keepLast=False, 674 vtk=True, 675 keepRegular=False, 676 keepParallel=False, 677 keepInterval=None, 678 removeAnalyzed=False, 679 clearHistory=False, 680 functionObjectData=False, 681 additional=[]):
682 """One-stop-shop to remove data 683 @param after: time after which directories ar to be removed 684 @param processor: remove the processorXX directories 685 @param pyfoam: rremove all directories typically created by PyFoam 686 @param keepLast: Keep the last time-step 687 @param additional: list with additional patterns to clear""" 688 self.clearResults(after=after, 689 removeProcs=processor, 690 keepLast=keepLast, 691 keepInterval=keepInterval, 692 vtk=vtk, 693 keepRegular=keepRegular, 694 keepParallel=keepParallel, 695 functionObjectData=functionObjectData, 696 additional=additional) 697 self.clearOther(pyfoam=pyfoam, 698 removeAnalyzed=removeAnalyzed, 699 clearHistory=clearHistory)
700
701 - def initialDir(self):
702 """@return: the name of the first time-directory (==initial 703 conditions) 704 @rtype: str""" 705 self.reread() 706 707 if self.first: 708 return path.join(self.name,self.first) 709 else: 710 if path.exists(path.join(self.name,"0.org")): 711 return path.join(self.name,"0.org") 712 else: 713 return None
714
715 - def latestDir(self):
716 """@return: the name of the first last-directory (==simulation 717 results) 718 @rtype: str""" 719 self.reread() 720 721 last=self.getLast() 722 if last: 723 return path.join(self.name,last) 724 else: 725 return None
726
727 - def constantDir(self,region=None,processor=None):
728 """@param region: Specify the region for cases with more than 1 mesh 729 @param processor: name of the processor directory 730 @return: the name of the C{constant}-directory 731 @rtype: str""" 732 pre=self.name 733 if processor!=None: 734 if type(processor)==int: 735 processor="processor%d" % processor 736 pre=path.join(pre,processor) 737 738 if region==None and self.region!=None: 739 region=self.region 740 if region: 741 return path.join(pre,"constant",region) 742 else: 743 return path.join(pre,"constant")
744
745 - def systemDir(self,region=None):
746 """@param region: Specify the region for cases with more than 1 mesh 747 @return: the name of the C{system}-directory 748 @rtype: str""" 749 if region==None and self.region!=None: 750 region=self.region 751 if region: 752 return path.join(self.name,"system",region) 753 else: 754 return path.join(self.name,"system")
755
756 - def controlDict(self):
757 """@return: the name of the C{controlDict} 758 @rtype: str""" 759 return path.join(self.systemDir(),"controlDict")
760
761 - def polyMeshDir(self,region=None,time=None,processor=None):
762 """@param region: Specify the region for cases with more than 1 mesh 763 @return: the name of the C{polyMesh} 764 @param time: Time for which the mesh should be looked at 765 @param processor: Name of the processor directory for decomposed cases 766 @rtype: str""" 767 if region==None and self.region!=None: 768 region=self.region 769 if time==None: 770 return path.join( 771 self.constantDir( 772 region=region, 773 processor=processor), 774 "polyMesh") 775 else: 776 return path.join( 777 TimeDirectory(self.name, 778 time, 779 region=region, 780 processor=processor).name, 781 "polyMesh")
782
783 - def boundaryDict(self,region=None,time=None,processor=None):
784 """@param region: Specify the region for cases with more than 1 mesh 785 @return: name of the C{boundary}-file 786 @rtype: str""" 787 if region==None and self.region!=None: 788 region=self.region 789 return path.join(self.polyMeshDir(region=region,time=time,processor=processor),"boundary")
790
791 - def blockMesh(self,region=None):
792 """@param region: Specify the region for cases with more than 1 mesh 793 @return: the name of the C{blockMeshDict} if it exists. Returns 794 an empty string if it doesn't 795 @rtype: str""" 796 if region==None and self.region!=None: 797 region=self.region 798 p=path.join(self.polyMeshDir(region=region),"blockMeshDict") 799 if path.exists(p): 800 return p 801 else: 802 return ""
803
804 - def makeFile(self,name):
805 """create a file in the solution directory and return a 806 corresponding BasicFile-object 807 808 @param name: Name of the file 809 @rtype: L{BasicFile}""" 810 return BasicFile(path.join(self.name,name))
811
812 - def getRegions(self,defaultRegion=False):
813 """Gets a list of all the available mesh regions by checking all 814 directories in constant and using all those that have a polyMesh-subdirectory 815 @param defaultRegion: should the default region also be added (as None)""" 816 lst=[] 817 for d in self.listDirectory(self.constantDir()): 818 if path.isdir(path.join(self.constantDir(),d)): 819 if path.exists(self.polyMeshDir(region=d)): 820 lst.append(d) 821 822 if defaultRegion: 823 if path.exists(self.polyMeshDir()): 824 lst.append(None) 825 826 lst.sort() 827 return lst
828
829 - def addToHistory(self,*text):
830 """Adds a line with date and username to a file 'PyFoamHistory' 831 that resides in the local directory""" 832 hist=open(path.join(self.name,"PyFoamHistory"),"a") 833 834 try: 835 # this seems to fail when no stdin is available 836 username=getlogin() 837 except OSError: 838 username=environ["USER"] 839 840 hist.write("%s by %s in %s :" % (asctime(),username,uname()[1])) 841 842 for t in text: 843 hist.write(str(t)+" ") 844 845 hist.write("\n") 846 hist.close()
847
848 - def listFiles(self,directory=None):
849 """List all the plain files (not directories) in a subdirectory 850 of the case 851 @param directory: the subdirectory. If unspecified the 852 case-directory itself is used 853 @return: List with the plain filenames""" 854 855 result=[] 856 theDir=self.name 857 if directory: 858 theDir=path.join(theDir,directory) 859 860 for f in listdir(theDir): 861 if f[0]!='.' and f[-1]!='~': 862 if path.isfile(path.join(theDir,f)): 863 result.append(f) 864 865 return result
866
867 - def getDictionaryText(self,directory,name):
868 """@param directory: Sub-directory of the case 869 @param name: name of the dictionary file 870 @return: the contents of the file as a big string""" 871 872 result=None 873 theDir=self.name 874 if directory: 875 theDir=path.join(theDir,directory) 876 877 if path.exists(path.join(theDir,name)): 878 result=open(path.join(theDir,name)).read() 879 else: 880 warning("File",name,"does not exist in directory",directory,"of case",self.name) 881 882 return result
883
884 - def writeDictionaryContents(self,directory,name,contents):
885 """Writes the contents of a dictionary 886 @param directory: Sub-directory of the case 887 @param name: name of the dictionary file 888 @param contents: Python-dictionary with the dictionary contents""" 889 890 theDir=self.name 891 if directory: 892 theDir=path.join(theDir,directory) 893 894 result=WriteParameterFile(path.join(theDir,name)) 895 result.content=contents 896 result.writeFile()
897
898 - def writeDictionaryText(self,directory,name,text):
899 """Writes the contents of a dictionary 900 @param directory: Sub-directory of the case 901 @param name: name of the dictionary file 902 @param text: String with the dictionary contents""" 903 904 theDir=self.name 905 if directory: 906 theDir=path.join(theDir,directory) 907 908 result=open(path.join(theDir,name),"w").write(text)
909
910 - def getDictionaryContents(self,directory,name):
911 """@param directory: Sub-directory of the case 912 @param name: name of the dictionary file 913 @return: the contents of the file as a python data-structure""" 914 915 result={} 916 theDir=self.name 917 if directory: 918 theDir=path.join(theDir,directory) 919 920 if path.exists(path.join(theDir,name)): 921 result=ParsedParameterFile(path.join(theDir,name)).content 922 else: 923 warning("File",name,"does not exist in directory",directory,"of case",self.name) 924 925 return result
926
927 - def determineVCS(self):
928 """Find out whether this directory is controlled by a VCS and 929 return the abbreviation of that VCS""" 930 931 if path.isdir(path.join(self.name,".hg")): 932 return "hg" 933 elif path.isdir(path.join(self.name,".git")): 934 return "git" 935 elif path.isdir(path.join(self.name,".svn")): 936 return "svn" 937 else: 938 return None
939
940 -class ChemkinSolutionDirectory(SolutionDirectory):
941 """Solution directory with a directory for the Chemkin-files""" 942 943 chemkinName = "chemkin" 944
945 - def __init__(self,name,archive="ArchiveDir"):
946 SolutionDirectory.__init__(self,name,archive=archive) 947 948 self.addToClone(self.chemkinName)
949
950 - def chemkinDir(self):
951 """@rtype: str 952 @return: The directory with the Chemkin-Files""" 953 954 return path.join(self.name,self.chemkinName)
955
956 -class NoTouchSolutionDirectory(SolutionDirectory):
957 """Convenience class that makes sure that nothing new is created""" 958
959 - def __init__(self, 960 name, 961 region=None):
962 SolutionDirectory.__init__(self, 963 name, 964 archive=None, 965 paraviewLink=False, 966 region=region)
967 968 # Should work with Python3 and Python2 969