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("--no-decompose",
78 dest="doDecompose",
79 action="store_false",
80 default=True,
81 help="Don't run the decomposer (only writes the dictionary")
82
83 self.parser.add_option("--decomposer",
84 dest="decomposer",
85 action="store",
86 default="decomposePar",
87 help="The decompose Utility that should be used")
88
89 self.parser.add_option("--foamVersion",
90 dest="foamVersion",
91 default=None,
92 help="Change the OpenFOAM-version that is to be used")
93
94 self.parser.add_option("--all-regions",
95 action="store_true",
96 default=False,
97 dest="regions",
98 help="Executes the command for all available regions (builds a pseudo-case for each region)")
99
100 self.parser.add_option("--region",
101 dest="region",
102 default=None,
103 help="Executes the command for a region (builds a pseudo-case for that region)")
104
105 self.parser.add_option("--keep-pseudocases",
106 action="store_true",
107 default=False,
108 dest="keeppseudo",
109 help="Keep the pseudo-cases that were built for a multi-region case")
110
112 if self.opts.keeppseudo and (not self.opts.regions and self.opts.region==None):
113 warning("Option --keep-pseudocases only makes sense for multi-region-cases")
114
115 nr=int(self.parser.getArgs()[1])
116 if nr<2:
117 error("Number of processors",nr,"too small (at least 2)")
118
119 case=self.parser.getArgs()[0]
120 method=self.opts.method
121
122 result={}
123 result["numberOfSubdomains"]=nr
124 result["method"]=method
125
126 coeff={}
127 result[method+"Coeffs"]=coeff
128
129 if method=="metis":
130 if self.opts.processorWeights!=None:
131 weigh=eval(self.opts.processorWeights)
132 if nr!=len(weigh):
133 error("Number of processors",nr,"and length of",weigh,"differ")
134 coeff["processorWeights"]=weigh
135 elif method=="manual":
136 if self.opts.dataFile==None:
137 error("Missing required option dataFile")
138 else:
139 coeff["dataFile"]="\""+self.opts.dataFile+"\""
140 elif method=="simple" or method=="hierarchical":
141 if self.opts.n==None or self.opts.delta==None:
142 error("Missing required option n or delta")
143 n=eval(self.opts.n)
144 if len(n)!=3:
145 error("Needs to be three elements, not",n)
146 if nr!=n[0]*n[1]*n[2]:
147 error("Subdomains",n,"inconsistent with processor number",nr)
148 coeff["n"]="(%d %d %d)" % (n[0],n[1],n[2])
149
150 coeff["delta"]=float(self.opts.delta)
151 if method=="hierarchical":
152 if self.opts.order==None:
153 error("Missing reuired option order")
154 if len(self.opts.order)!=3:
155 error("Order needs to be three characters")
156 coeff["order"]=self.opts.order
157 else:
158 error("Method",method,"not yet implementes")
159
160 gen=FoamFileGenerator(result)
161
162 if self.opts.test:
163 print str(gen)
164 sys.exit(-1)
165 else:
166 f=open(path.join(case,"system","decomposeParDict"),"w")
167 writeDictionaryHeader(f)
168 f.write(str(gen))
169 f.close()
170
171 if self.opts.clear:
172 system("rm -rf "+path.join(case,"processor*"))
173
174 if self.opts.doDecompose:
175 regionNames=[self.opts.region]
176 regions=None
177
178 if self.opts.regions or self.opts.region!=None:
179 print "Building Pseudocases"
180 sol=SolutionDirectory(case)
181 regions=RegionCases(sol,clean=True)
182
183 if self.opts.regions:
184 regionNames=sol.getRegions()
185
186 for theRegion in regionNames:
187 theCase=case
188 if theRegion!=None:
189 theCase+="."+theRegion
190
191 run=UtilityRunner(argv=[self.opts.decomposer,".",theCase],silent=False,server=False)
192 run.start()
193
194 if theRegion!=None:
195 print "Syncing into master case"
196 regions.resync(theRegion)
197
198 if regions!=None:
199 if not self.opts.keeppseudo:
200 print "Removing pseudo-regions"
201 regions.cleanAll()
202 else:
203 for r in sol.getRegions():
204 if r not in regionNames:
205 regions.clean(r)
206