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