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

Source Code for Module PyFoam.RunDictionary.SolutionDirectory

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