1
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
12 from PyFoam.Execution.UtilityRunner import UtilityRunner
13 from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
14 from PyFoam.RunDictionary.RegionCases import RegionCases
15 from PyFoam.FoamInformation import oldAppConvention as oldApp
16
17 from CommonMultiRegion import CommonMultiRegion
18 from CommonStandardOutput import CommonStandardOutput
19 from CommonServer import CommonServer
20
21 from os import path,system
22 import sys,string
23
24 -class Decomposer(PyFoamApplication,
25 CommonStandardOutput,
26 CommonServer,
27 CommonMultiRegion):
38
39 decomposeChoices=["metis","simple","hierarchical","manual"]
40
42 spec=OptionGroup(self.parser,
43 "Decomposition Specification",
44 "How the case should be decomposed")
45 spec.add_option("--method",
46 type="choice",
47 default="metis",
48 dest="method",
49 action="store",
50 choices=self.decomposeChoices,
51 help="The method used for decomposing (Choices: "+string.join(self.decomposeChoices,", ")+") Default: %default")
52
53 spec.add_option("--n",
54 dest="n",
55 action="store",
56 default=None,
57 help="Number of subdivisions in coordinate directions. A python list or tuple (for simple and hierarchical)")
58
59 spec.add_option("--delta",
60 dest="delta",
61 action="store",
62 type="float",
63 default=None,
64 help="Cell skew factor (for simple and hierarchical)")
65
66 spec.add_option("--order",
67 dest="order",
68 action="store",
69 default=None,
70 help="Order of decomposition (for hierarchical)")
71
72 spec.add_option("--processorWeights",
73 dest="processorWeights",
74 action="store",
75 default=None,
76 help="The weights of the processors. A python list. Used for metis")
77
78 spec.add_option("--dataFile",
79 dest="dataFile",
80 action="store",
81 default=None,
82 help="File with the allocations. (for manual)")
83 self.parser.add_option_group(spec)
84
85 behave=OptionGroup(self.parser,
86 "Decomposition behaviour",
87 "How the program should behave during decomposition")
88 behave.add_option("--test",
89 dest="test",
90 action="store_true",
91 default=False,
92 help="Just print the resulting dictionary")
93
94 behave.add_option("--clear",
95 dest="clear",
96 action="store_true",
97 default=False,
98 help="Clear the case of previous processor directories")
99
100 behave.add_option("--no-decompose",
101 dest="doDecompose",
102 action="store_false",
103 default=True,
104 help="Don't run the decomposer (only writes the dictionary")
105
106 behave.add_option("--decomposer",
107 dest="decomposer",
108 action="store",
109 default="decomposePar",
110 help="The decompose Utility that should be used")
111 self.parser.add_option_group(behave)
112
113 CommonMultiRegion.addOptions(self)
114 CommonStandardOutput.addOptions(self)
115 CommonServer.addOptions(self,False)
116
118 if self.opts.keeppseudo and (not self.opts.regions and self.opts.region==None):
119 warning("Option --keep-pseudocases only makes sense for multi-region-cases")
120
121 nr=int(self.parser.getArgs()[1])
122 if nr<2:
123 error("Number of processors",nr,"too small (at least 2)")
124
125 case=self.parser.getArgs()[0]
126 method=self.opts.method
127
128 result={}
129 result["numberOfSubdomains"]=nr
130 result["method"]=method
131
132 coeff={}
133 result[method+"Coeffs"]=coeff
134
135 if method=="metis":
136 if self.opts.processorWeights!=None:
137 weigh=eval(self.opts.processorWeights)
138 if nr!=len(weigh):
139 error("Number of processors",nr,"and length of",weigh,"differ")
140 coeff["processorWeights"]=weigh
141 elif method=="manual":
142 if self.opts.dataFile==None:
143 error("Missing required option dataFile")
144 else:
145 coeff["dataFile"]="\""+self.opts.dataFile+"\""
146 elif method=="simple" or method=="hierarchical":
147 if self.opts.n==None or self.opts.delta==None:
148 error("Missing required option n or delta")
149 n=eval(self.opts.n)
150 if len(n)!=3:
151 error("Needs to be three elements, not",n)
152 if nr!=n[0]*n[1]*n[2]:
153 error("Subdomains",n,"inconsistent with processor number",nr)
154 coeff["n"]="(%d %d %d)" % (n[0],n[1],n[2])
155
156 coeff["delta"]=float(self.opts.delta)
157 if method=="hierarchical":
158 if self.opts.order==None:
159 error("Missing reuired option order")
160 if len(self.opts.order)!=3:
161 error("Order needs to be three characters")
162 coeff["order"]=self.opts.order
163 else:
164 error("Method",method,"not yet implementes")
165
166 gen=FoamFileGenerator(result)
167
168 if self.opts.test:
169 print str(gen)
170 sys.exit(-1)
171 else:
172 f=open(path.join(case,"system","decomposeParDict"),"w")
173 writeDictionaryHeader(f)
174 f.write(str(gen))
175 f.close()
176
177 if self.opts.clear:
178 system("rm -rf "+path.join(case,"processor*"))
179
180 if self.opts.doDecompose:
181 regionNames=[self.opts.region]
182 regions=None
183
184 if self.opts.regions or self.opts.region!=None:
185 print "Building Pseudocases"
186 sol=SolutionDirectory(case)
187 regions=RegionCases(sol,clean=True)
188
189 if self.opts.regions:
190 regionNames=sol.getRegions()
191
192 for theRegion in regionNames:
193 theCase=path.normpath(case)
194 if theRegion!=None:
195 theCase+="."+theRegion
196
197 if oldApp():
198 argv=[self.opts.decomposer,".",theCase]
199 else:
200 argv=[self.opts.decomposer,"-case",theCase]
201
202 self.setLogname(default="Decomposer",useApplication=False)
203
204 run=UtilityRunner(argv=argv,
205 silent=self.opts.progress,
206 logname=self.opts.logname,
207 server=self.opts.server,
208 noLog=self.opts.noLog)
209 run.start()
210
211 if theRegion!=None:
212 print "Syncing into master case"
213 regions.resync(theRegion)
214
215 if regions!=None:
216 if not self.opts.keeppseudo:
217 print "Removing pseudo-regions"
218 regions.cleanAll()
219 else:
220 for r in sol.getRegions():
221 if r not in regionNames:
222 regions.clean(r)
223