1
2 """
3 Class that implements pyFoamDecompose
4 """
5
6 from PyFoamApplication import PyFoamApplication
7 from PyFoam.FoamInformation import changeFoamVersion
8 from PyFoam.Basics.FoamFileGenerator import FoamFileGenerator
9 from PyFoam.Error import error
10 from PyFoam.Basics.Utilities import writeDictionaryHeader
11 from PyFoam.Execution.UtilityRunner import UtilityRunner
12 from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
13 from PyFoam.RunDictionary.RegionCases import RegionCases
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,args=args,description=description,usage="%prog [options] <case> <procnr>",interspersed=True,nr=2)
24
26 self.parser.add_option("--method",
27 type="choice",
28 default="metis",
29 dest="method",
30 action="store",
31 choices=["metis","simple","hierarchical","manual"],
32 help="The method used for decomposing")
33
34 self.parser.add_option("--test",
35 dest="test",
36 action="store_true",
37 default=False,
38 help="Just print the resulting dictionary")
39
40 self.parser.add_option("--n",
41 dest="n",
42 action="store",
43 default=None,
44 help="Number of subdivisions in coordinate directions. A python list or tuple (for simple and hierarchical)")
45
46 self.parser.add_option("--delta",
47 dest="delta",
48 action="store",
49 type="float",
50 default=None,
51 help="Cell skew factor (for simple and hierarchical)")
52
53 self.parser.add_option("--order",
54 dest="order",
55 action="store",
56 default=None,
57 help="Order of decomposition (for hierarchical)")
58
59 self.parser.add_option("--processorWeights",
60 dest="processorWeights",
61 action="store",
62 default=None,
63 help="The weights of the processors. A python list. Used for metis")
64
65 self.parser.add_option("--dataFile",
66 dest="dataFile",
67 action="store",
68 default=None,
69 help="File with the allocations. (for manual)")
70
71 self.parser.add_option("--clear",
72 dest="clear",
73 action="store_true",
74 default=False,
75 help="Clear the case of previous processor directories")
76
77 self.parser.add_option("--silent",
78 dest="silent",
79 action="store_true",
80 default=False,
81 help="Don't print the output to the screen")
82
83 self.parser.add_option("--logname",
84 dest="log",
85 action="store",
86 default="Decomposer",
87 help="Filename for the output of the decompose-command")
88
89 self.parser.add_option("--no-decompose",
90 dest="doDecompose",
91 action="store_false",
92 default=True,
93 help="Don't run the decomposer (only writes the dictionary")
94
95 self.parser.add_option("--decomposer",
96 dest="decomposer",
97 action="store",
98 default="decomposePar",
99 help="The decompose Utility that should be used")
100
101 self.parser.add_option("--foamVersion",
102 dest="foamVersion",
103 default=None,
104 help="Change the OpenFOAM-version that is to 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 run=UtilityRunner(argv=[self.opts.decomposer,".",theCase],silent=self.opts.silent,logname=self.opts.log,server=False)
204 run.start()
205
206 if theRegion!=None:
207 print "Syncing into master case"
208 regions.resync(theRegion)
209
210 if regions!=None:
211 if not self.opts.keeppseudo:
212 print "Removing pseudo-regions"
213 regions.cleanAll()
214 else:
215 for r in sol.getRegions():
216 if r not in regionNames:
217 regions.clean(r)
218