1 """
2 Application-class that implements pyFoamInitGgiInterface.py
3
4 Inititialize various ggi interface attributes in the
5 constant/polymesh/boundary file, and in the time directories.
6
7 Backups of the boundary file is created.
8
9 Generate companion scripts for initializing the ggi zone faceSets.
10
11 Modify the decomposeParDict file for the new ggi zones names.
12
13 Author:
14 Martin Beaudoin, Hydro-Quebec, 2012. All rights reserved
15
16 """
17
18 import sys, fnmatch, re
19 from os import path, listdir, chmod
20 from stat import *
21
22 from PyFoam.Applications.PyFoamApplication import PyFoamApplication
23 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile
24 from PyFoam.ThirdParty.six import print_
25 from PyFoam.RunDictionary.TimeDirectory import TimeDirectory
26 from PyFoam.Basics.BasicFile import BasicFile
27
30 description="""
31 Init GGI boundary condition parameters in boundary file.
32 Init GGI boundary fields in time directories.
33 Generate faceSet scripts for ggi zones.
34 Modify GGI zones information in decomposeParDict file.
35 """
36 PyFoamApplication.__init__(self,
37 args=args,
38 description=description,
39 usage="%prog <caseDirectory> ggi_MasterPatchName ggi_ShadowPatchName",
40 interspersed=True,
41 changeVersion=False,
42 nr=3)
43
45 self.parser.add_option("--type",
46 action="store",
47 dest="ggiType",
48 default='ggi',
49 help='ggi type: ggi | cyclicGgi | overlapGgi')
50 self.parser.add_option("--patchZoneName",
51 action="store",
52 dest="patchZoneName",
53 default=None,
54 help='Name of the zone for the GGI patch')
55 self.parser.add_option("--bridgeOverlapFlag",
56 action="store",
57 dest="bridgeOverlapFlag",
58 default=None,
59 help='bridgeOverlap flag (on/off)')
60 self.parser.add_option("--rotationAxis",
61 action="store",
62 dest="rotationAxis",
63 default=None,
64 help='rotation axis for cyclicGgi or overlapGgi')
65 self.parser.add_option("--rotationAngle",
66 action="store",
67 dest="rotationAngle",
68 default=None,
69 help='rotation axis angle for cyclicGgi. Accept Python math expressions like 360.0/17.0')
70 self.parser.add_option("--separationOffset",
71 action="store",
72 dest="separationOffset",
73 default=None,
74 help='separation offset for cyclicGgi')
75 self.parser.add_option("--nCopies",
76 action="store",
77 dest="nCopies",
78 default=None,
79 help='number of copies for overlapGgi')
80 self.parser.add_option("--timeDirs",
81 action="store",
82 dest="timeDirs",
83 default=None,
84 help='time directories for modifying the ggi boundaryfields. Accept expressions like "[0-9]*", "0", etc.')
85
86 self.parser.add_option("--genFaceSetForGgiZonesScriptName",
87 action="store",
88 dest="genFaceSetForGgiZonesScriptName",
89 default="genFaceSetForGgiZones.setSet",
90 help='setSet batch file for generating faceSets for GGI zones. Default: genFaceSetForGgiZones.setSet')
91
92 self.parser.add_option("--initGgiZonesScriptName",
93 action="store",
94 dest="initGgiZonesScriptName",
95 default="initGgiZones.sh",
96 help='script name for initializing the GGI zone faceSets. Default: initGgiZones.sh')
97
98 self.parser.add_option("--test",
99 action="store_true",
100 default=False,
101 dest="test",
102 help="Only print the new boundary file")
103
105 description="""\
106 Create a default definition for a ggi patch, and replace
107 the current definition
108 """
109 print_("Replacing definition of patch: ", patchName, ":", patch)
110 newPatch={
111 'type' : ggiType,
112 'nFaces' : patch["nFaces"],
113 'startFace' : patch["startFace"],
114 'shadowPatch' : 'unknown',
115 'zone' : patchName+'Zone',
116 'bridgeOverlap' : 'true',
117 'rotationAxis' : '(0 0 1)',
118 'rotationAngle' : '0.0',
119 'separationOffset' : '(0 0 0)'
120 }
121 return newPatch
122
124 description="""\
125 Modify the definition of a ggi patch
126 """
127 print_(" Modifying ggi boundary definition in constant/polyMesh/boundary for patch", patchName)
128
129 patch["type"]=ggiType
130
131 patch["shadowPatch"]=shadowName
132
133 if self.parser.getOptions().patchZoneName!=None:
134 patch["zone"]=self.parser.getOptions().patchZoneName
135 else:
136 patch["zone"]=patchName+'Zone'
137
138 if self.parser.getOptions().bridgeOverlapFlag!=None:
139 patch["bridgeOverlap"]=self.parser.getOptions().bridgeOverlapFlag
140
141 if ggiType=="cyclicGgi":
142 if self.parser.getOptions().rotationAxis!=None:
143 patch["rotationAxis"]=self.parser.getOptions().rotationAxis
144
145
146
147 if self.parser.getOptions().rotationAngle!=None:
148 patch["rotationAngle"]=rotationAngle
149
150 if self.parser.getOptions().separationOffset!=None:
151 patch["separationOffset"]=self.parser.getOptions().separationOffset
152
153 if ggiType=="overlapGgi":
154 if self.parser.getOptions().rotationAxis!=None:
155 patch["rotationAxis"]=self.parser.getOptions().rotationAxis
156
157 if self.parser.getOptions().nCopies!=None:
158 patch["nCopies"]=self.parser.getOptions().nCopies
159
160
162 description="""\
163 Modify the definition of a ggi patch in the time directories
164 """
165 regex = fnmatch.translate(timeDirs)
166
167 reobj = re.compile(regex)
168
169 for timeDir in listdir(caseDir):
170 if reobj.match(timeDir):
171 print_(" Modifying ggi boundaryFields in timeDir", timeDir, "for patch", patchName)
172
173 td=TimeDirectory(caseDir, timeDir, yieldParsedFiles=True)
174
175 for f in td:
176 print_(" Modifying field", f.name)
177 f["boundaryField"][patchName]["type"]=ggiType
178 f.writeFile()
179
180
182 description="""\
183 Generate a setSet batch file based on the zone info specified in the ggi interfaces definition.
184 Generate a bash file for invoking setSet and setsToZones
185 Update GGI zone infoprmation in decomposeParDict
186 """
187
188 bfGenFaceSets = BasicFile(path.join(caseDir, self.parser.getOptions().genFaceSetForGgiZonesScriptName))
189
190 print_(" Updating file ", bfGenFaceSets.name, " for generating GGI zones faceSet using the setSet command")
191
192 bnd=boundary.content
193
194 if type(bnd)!=list:
195 self.error("Problem with boundary file (not a list)")
196
197
198 listOfGgiZones = []
199
200 for index in range(0, len(bnd), 2):
201 patchName = bnd[index]
202 indexDefPatch=index+1
203 if bnd[indexDefPatch]["type"]=='ggi' or bnd[indexDefPatch]["type"]=='cyclicGgi' or bnd[indexDefPatch]["type"]=='overlapGgi':
204 bfGenFaceSets.writeLine([ "faceSet " + bnd[indexDefPatch]["zone"] + " new patchToFace "+ patchName ])
205 listOfGgiZones.append(bnd[indexDefPatch]["zone"])
206
207 bfGenFaceSets.writeLine([ "quit" ])
208 bfGenFaceSets.close()
209
210
211 bfInitGgiZones = BasicFile(path.join(caseDir, self.parser.getOptions().initGgiZonesScriptName))
212
213 print_(" Updating file ", bfInitGgiZones.name, " for inititalizing GGI zones")
214
215 bfInitGgiZones.writeLine([ "#!/bin/bash" ])
216 bfInitGgiZones.writeLine([ "setSet -batch " + self.parser.getOptions().genFaceSetForGgiZonesScriptName ])
217 bfInitGgiZones.writeLine([ "setsToZones -noFlipMap" ])
218 bfInitGgiZones.close()
219
220
221 chmod(bfInitGgiZones.name, S_IRWXU|S_IRGRP|S_IXGRP|S_IXOTH|S_IROTH)
222
223
224 decomposeParDictPath=path.join(caseDir,"system","decomposeParDict")
225 if path.exists(decomposeParDictPath):
226 print_(" Updating file ", decomposeParDictPath, " for GGI zones")
227 decomposeParDict=ParsedParameterFile(decomposeParDictPath,debug=False,backup=True)
228 dcp=decomposeParDict.content
229 dcp["globalFaceZones"]="(\n " + '\n '.join(list(listOfGgiZones)) + "\n)"
230 decomposeParDict.writeFile()
231
233 caseDir=self.parser.getArgs()[0]
234 masterbName=self.parser.getArgs()[1]
235 shadowbName=self.parser.getArgs()[2]
236
237 boundary=ParsedParameterFile(path.join(".",caseDir,"constant","polyMesh","boundary"),debug=False,boundaryDict=True,backup=True)
238
239 bnd=boundary.content
240
241 if type(bnd)!=list:
242 self.error("Problem with boundary file (not a list)")
243
244 masterFound=False
245 shadowFound=False
246 updateTimeDirs=False
247
248 timeDirs="0"
249 if self.parser.getOptions().timeDirs!=None:
250 timeDirs=self.parser.getOptions().timeDirs
251 updateTimeDirs=True
252
253 ggiType=self.parser.getOptions().ggiType
254
255 rotationAngle=0.0
256 if self.parser.getOptions().rotationAngle!=None:
257 rotationAngle=float(eval(self.parser.getOptions().rotationAngle))
258
259 for index in range(len(bnd)):
260 indexDefPatch=index+1
261
262 if bnd[index]==masterbName:
263 masterFound=True
264 if bnd[indexDefPatch]["type"]!=ggiType:
265 bnd[indexDefPatch] = self.createGGIPatch(bnd[indexDefPatch], masterbName, ggiType)
266
267 self.modifyGGIPatchDefinition(bnd[indexDefPatch], masterbName, shadowbName, ggiType, rotationAngle)
268
269 if updateTimeDirs:
270 self.modifyGGIPatchDefinitionInTimeDirs(caseDir, masterbName, ggiType, timeDirs)
271
272 elif bnd[index]==shadowbName:
273 shadowFound=True
274 if bnd[indexDefPatch]["type"]!=ggiType:
275 bnd[indexDefPatch] = self.createGGIPatch(bnd[indexDefPatch], shadowbName, ggiType)
276 self.modifyGGIPatchDefinition(bnd[indexDefPatch], shadowbName, masterbName, ggiType, -rotationAngle)
277
278 if updateTimeDirs:
279 self.modifyGGIPatchDefinitionInTimeDirs(caseDir, shadowbName, ggiType, timeDirs)
280
281 if masterFound and shadowFound:
282 break;
283
284 if not masterFound:
285 self.error("Boundary patch",masterbName,"not found in",bnd[::2])
286
287 if not shadowFound:
288 self.error("Boundary patch",shadowbName,"not found in",bnd[::2])
289
290 if self.parser.getOptions().test:
291 print_(boundary)
292 else:
293 boundary.writeFile()
294
295
296 self.generateCompanionFiles(caseDir, boundary)
297