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