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

Source Code for Module PyFoam.Applications.Decomposer

  1  #  ICE Revision: $Id: /local/openfoam/Python/PyFoam/PyFoam/Applications/Decomposer.py 7930 2012-03-14T12:33:54.771148Z bgschaid  $  
  2  """ 
  3  Class that implements pyFoamDecompose 
  4  """ 
  5   
  6  from optparse import OptionGroup 
  7   
  8  from PyFoamApplication import PyFoamApplication 
  9  from PyFoam.Basics.FoamFileGenerator import FoamFileGenerator 
 10  from PyFoam.Error import error 
 11  from PyFoam.Basics.Utilities import writeDictionaryHeader,rmtree 
 12  from PyFoam.Execution.UtilityRunner import UtilityRunner 
 13  from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory 
 14  from PyFoam.RunDictionary.RegionCases import RegionCases 
 15  from PyFoam.RunDictionary.ParsedParameterFile import FoamStringParser 
 16  from PyFoam.FoamInformation import oldAppConvention as oldApp 
 17  from PyFoam.FoamInformation import foamVersion 
 18   
 19  from CommonMultiRegion import CommonMultiRegion 
 20  from CommonStandardOutput import CommonStandardOutput 
 21  from CommonServer import CommonServer 
 22  from CommonVCSCommit import CommonVCSCommit 
 23   
 24  from os import path,listdir,symlink 
 25  import sys,string 
 26   
27 -class Decomposer(PyFoamApplication, 28 CommonStandardOutput, 29 CommonServer, 30 CommonMultiRegion, 31 CommonVCSCommit):
32 - def __init__(self,args=None):
33 description="""\ 34 Generates a decomposeParDict for a case and runs the decompose-Utility 35 on that case 36 """ 37 PyFoamApplication.__init__(self, 38 args=args, 39 description=description, 40 usage="%prog [options] <case> <procnr>", 41 interspersed=True, 42 nr=2)
43 44 decomposeChoices=["metis","simple","hierarchical","manual"] 45 defaultMethod="metis" 46
47 - def addOptions(self):
48 if foamVersion()>=(1,6): 49 self.defaultMethod="scotch" 50 self.decomposeChoices+=[self.defaultMethod] 51 self.decomposeChoices+=["parMetis"] 52 53 spec=OptionGroup(self.parser, 54 "Decomposition Specification", 55 "How the case should be decomposed") 56 spec.add_option("--method", 57 type="choice", 58 default=self.defaultMethod, 59 dest="method", 60 action="store", 61 choices=self.decomposeChoices, 62 help="The method used for decomposing (Choices: "+string.join(self.decomposeChoices,", ")+") Default: %default") 63 64 spec.add_option("--n", 65 dest="n", 66 action="store", 67 default=None, 68 help="Number of subdivisions in coordinate directions. A python list or tuple (for simple and hierarchical)") 69 70 spec.add_option("--delta", 71 dest="delta", 72 action="store", 73 type="float", 74 default=None, 75 help="Cell skew factor (for simple and hierarchical)") 76 77 spec.add_option("--order", 78 dest="order", 79 action="store", 80 default=None, 81 help="Order of decomposition (for hierarchical)") 82 83 spec.add_option("--processorWeights", 84 dest="processorWeights", 85 action="store", 86 default=None, 87 help="The weights of the processors. A python list. Used for metis, scotch and parMetis") 88 89 spec.add_option("--globalFaceZones", 90 dest="globalFaceZones", 91 action="store", 92 default=None, 93 help="""Global face zones. A string with a python list or an OpenFOAM-list of words. Used for the GGI interface. Ex: '["GGI_Z1","GGI_Z2"]' or '(GGI_Z1 GGI_Z2)'""") 94 95 spec.add_option("--dataFile", 96 dest="dataFile", 97 action="store", 98 default=None, 99 help="File with the allocations. (for manual)") 100 self.parser.add_option_group(spec) 101 102 behave=OptionGroup(self.parser, 103 "Decomposition behaviour", 104 "How the program should behave during decomposition") 105 behave.add_option("--test", 106 dest="test", 107 action="store_true", 108 default=False, 109 help="Just print the resulting dictionary") 110 111 behave.add_option("--clear", 112 dest="clear", 113 action="store_true", 114 default=False, 115 help="Clear the case of previous processor directories") 116 117 behave.add_option("--no-decompose", 118 dest="doDecompose", 119 action="store_false", 120 default=True, 121 help="Don't run the decomposer (only writes the dictionary") 122 123 behave.add_option("--decomposer", 124 dest="decomposer", 125 action="store", 126 default="decomposePar", 127 help="The decompose Utility that should be used") 128 self.parser.add_option_group(behave) 129 130 work=OptionGroup(self.parser, 131 "Additional work", 132 "What else should be done in addition to decomposing") 133 work.add_option("--constant-link", 134 dest="doConstantLinks", 135 action="store_true", 136 default=False, 137 help="Add links to the contents of the constant directory to the constant directories of the processor-directories") 138 self.parser.add_option_group(work) 139 140 CommonMultiRegion.addOptions(self) 141 CommonStandardOutput.addOptions(self) 142 CommonServer.addOptions(self,False) 143 CommonVCSCommit.addOptions(self)
144
145 - def run(self):
146 decomposeParWithRegion=(foamVersion()>=(1,6)) 147 148 if self.opts.keeppseudo and (not self.opts.regions and self.opts.region==None): 149 warning("Option --keep-pseudocases only makes sense for multi-region-cases") 150 151 if decomposeParWithRegion and self.opts.keeppseudo: 152 warning("Option --keep-pseudocases doesn't make sense since OpenFOAM 1.6 because decomposePar supports regions") 153 154 nr=int(self.parser.getArgs()[1]) 155 if nr<2: 156 error("Number of processors",nr,"too small (at least 2)") 157 158 case=path.abspath(self.parser.getArgs()[0]) 159 method=self.opts.method 160 161 result={} 162 result["numberOfSubdomains"]=nr 163 result["method"]=method 164 165 coeff={} 166 result[method+"Coeffs"]=coeff 167 168 if self.opts.globalFaceZones!=None: 169 try: 170 fZones=eval(self.opts.globalFaceZones) 171 except SyntaxError: 172 fZones=FoamStringParser( 173 self.opts.globalFaceZones, 174 listDict=True 175 ).data 176 177 result["globalFaceZones"]=fZones 178 179 if method in ["metis","scotch","parMetis"]: 180 if self.opts.processorWeights!=None: 181 weigh=eval(self.opts.processorWeights) 182 if nr!=len(weigh): 183 error("Number of processors",nr,"and length of",weigh,"differ") 184 coeff["processorWeights"]=weigh 185 elif method=="manual": 186 if self.opts.dataFile==None: 187 error("Missing required option dataFile") 188 else: 189 coeff["dataFile"]="\""+self.opts.dataFile+"\"" 190 elif method=="simple" or method=="hierarchical": 191 if self.opts.n==None or self.opts.delta==None: 192 error("Missing required option n or delta") 193 n=eval(self.opts.n) 194 if len(n)!=3: 195 error("Needs to be three elements, not",n) 196 if nr!=n[0]*n[1]*n[2]: 197 error("Subdomains",n,"inconsistent with processor number",nr) 198 coeff["n"]="(%d %d %d)" % (n[0],n[1],n[2]) 199 200 coeff["delta"]=float(self.opts.delta) 201 if method=="hierarchical": 202 if self.opts.order==None: 203 error("Missing reuired option order") 204 if len(self.opts.order)!=3: 205 error("Order needs to be three characters") 206 coeff["order"]=self.opts.order 207 else: 208 error("Method",method,"not yet implementes") 209 210 gen=FoamFileGenerator(result) 211 212 if self.opts.test: 213 print str(gen) 214 return -1 215 else: 216 f=open(path.join(case,"system","decomposeParDict"),"w") 217 writeDictionaryHeader(f) 218 f.write(str(gen)) 219 f.close() 220 221 if self.opts.clear: 222 rmtree(path.join(case,"processor*"),ignore_errors=True) 223 224 self.checkAndCommit(SolutionDirectory(case,archive=None)) 225 226 if self.opts.doDecompose: 227 if self.opts.region: 228 regionNames=self.opts.region[:] 229 while True: 230 try: 231 i=regionNames.index("region0") 232 regionNames[i]=None 233 except ValueError: 234 break 235 else: 236 regionNames=[None] 237 238 regions=None 239 240 sol=SolutionDirectory(case) 241 if not decomposeParWithRegion: 242 if self.opts.regions or self.opts.region!=None: 243 print "Building Pseudocases" 244 regions=RegionCases(sol,clean=True,processorDirs=False) 245 246 if self.opts.regions: 247 regionNames=sol.getRegions(defaultRegion=True) 248 249 for theRegion in regionNames: 250 theCase=path.normpath(case) 251 if theRegion!=None and not decomposeParWithRegion: 252 theCase+="."+theRegion 253 254 if oldApp(): 255 argv=[self.opts.decomposer,".",theCase] 256 else: 257 argv=[self.opts.decomposer,"-case",theCase] 258 if theRegion!=None and decomposeParWithRegion: 259 argv+=["-region",theRegion] 260 261 f=open(path.join(case,"system",theRegion,"decomposeParDict"),"w") 262 writeDictionaryHeader(f) 263 f.write(str(gen)) 264 f.close() 265 266 self.setLogname(default="Decomposer",useApplication=False) 267 268 run=UtilityRunner(argv=argv, 269 silent=self.opts.progress or self.opts.silent, 270 logname=self.opts.logname, 271 compressLog=self.opts.compress, 272 server=self.opts.server, 273 noLog=self.opts.noLog, 274 logTail=self.opts.logTail, 275 jobId=self.opts.jobId) 276 run.start() 277 278 if theRegion!=None and not decomposeParWithRegion: 279 print "Syncing into master case" 280 regions.resync(theRegion) 281 282 if regions!=None and not decomposeParWithRegion: 283 if not self.opts.keeppseudo: 284 print "Removing pseudo-regions" 285 regions.cleanAll() 286 else: 287 for r in sol.getRegions(): 288 if r not in regionNames: 289 regions.clean(r) 290 291 if self.opts.doConstantLinks: 292 print "Adding symlinks in the constant directories" 293 constPath=path.join(case,"constant") 294 for f in listdir(constPath): 295 srcExpr=path.join(path.pardir,path.pardir,"constant",f) 296 for p in range(nr): 297 dest=path.join(case,"processor%d"%p,"constant",f) 298 if not path.exists(dest): 299 symlink(srcExpr,dest) 300 301 self.addToCaseLog(case)
302