1 """
2 Represents the actual CaseBuilder-File and other things that have to do with the Casebuilder
3 """
4
5 from xml.dom.minidom import parse
6 import xml.dom
7 from os import path
8 import os
9 import shutil
10 import glob
11
12 from PyFoam.Error import error,warning
13 from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,FoamStringParser
14 from PyFoam.Execution.BasicRunner import BasicRunner
15 from PyFoam.FoamInformation import oldAppConvention as oldApp
16 from CreateBoundaryPatches import CreateBoundaryPatches
17 from PyFoam import configuration as config
18 from PyFoam.Basics.DataStructures import Vector
19
21 """Gets a list of the case-builder files found in the current path"""
30
32 for f in self.list:
33 yield f
34
37
40
42 """Wraps the argument element for convenient access"""
45
47 if name=="type":
48 tmp=self.el.getElementsByTagName("verify")
49 if len(tmp)!=1:
50 return None
51 val=tmp[0].getElementsByTagName("validator")
52 if len(val)!=1:
53 return None
54 else:
55 return val[0].getAttribute("type")
56 elif name=="values":
57 tmp=self.el.getElementsByTagName("verify")
58 if len(tmp)!=1:
59 return None
60 val=tmp[0].getElementsByTagName("validator")
61 if len(val)!=1:
62 return None
63 else:
64 return map(str,val[0].getAttribute("values").split("|"))
65 else:
66 return self.el.getAttribute(name)
67
69 """
70 This class reads an XML-file that describes how to build a case
71 and gives information about the case and if asked to builds the actual case
72 """
73
75 """@param fName: the XML-file that describes how to build the case"""
76
77 dom=parse(fName)
78 self.doc=dom.documentElement
79
80 if self.doc.tagName!='casebuilder':
81 error("Wrong root-element",self.doc.tagName,"Expected: 'casebuilder'")
82
84 return self.doc.getAttribute("name")
85
87 return self.doc.getAttribute("description")
88
90 ht=self.getSingleElement(self.doc,"helptext",optional=True)
91 if ht:
92 return ht.firstChild.nodeValue
93 else:
94 return "<No help text>"
95
98
101
104
107
110
113
115 return self.expandVars(self.doc.getAttribute("template"))
116
118 tmp=self.doc.getAttribute("initialdir")
119 if tmp=="":
120 tmp="0"
121 return tmp
122
124 orig=path.expanduser(orig)
125 orig=path.expandvars(orig)
126 if keys!=None:
127 orig=orig % keys
128 return orig
129
137
145
147 res={}
148 for nm,pat in self.boundaryPatterns():
149 res[nm]=pat
150 return res
151
153 bounds={}
154
155 for a in self.boundaryTree().getElementsByTagName("boundary"):
156 bounds[a.getAttribute("name")]=a.getAttribute("description")
157
158 return bounds
159
161 args=[]
162
163 for a in self.argTree().getElementsByTagName("argumentgroup"):
164 args.append(a.getAttribute("name"))
165
166 return args
167
169 args={}
170
171 for a in self.argTree().getElementsByTagName("argumentgroup"):
172 args[a.getAttribute("name")]=a.getAttribute("description")
173
174 return args
175
177 args=[]
178
179 for a in self.argTree().getElementsByTagName("arg"):
180 args.append(a.getAttribute("name"))
181
182 return args
183
185 args={}
186
187 for a in self.argTree().getElementsByTagName("arg"):
188 args[a.getAttribute("name")]=ArgWrapper(a)
189
190 return args
191
193 """Returns a list with the arguments belongin to a specific group
194 @param name: Name of the group. If none is given, then all the arguments
195 belonging to no group are returned"""
196
197 result=[]
198
199 for c in self.argTree().childNodes:
200 if "tagName" in dir(c):
201 if c.tagName=="arg" and name==None:
202 result.append(c.getAttribute("name"))
203 elif c.tagName=="argumentgroup":
204 if c.getAttribute("name")==name:
205 for e in c.getElementsByTagName("arg"):
206 result.append(e.getAttribute("name"))
207
208 return result
209
211 args={}
212
213 for a in self.argTree().getElementsByTagName("arg"):
214 args[a.getAttribute("name")]=a.getAttribute("description")
215
216 return args
217
219 args={}
220
221 for a in self.argTree().getElementsByTagName("arg"):
222 args[a.getAttribute("name")]=a.getAttribute("default")
223
224 return args
225
227 """Get an element and check that it is the only one
228 @param parent: the parent element
229 @param name: The name of the element"""
230
231 tmp=parent.getElementsByTagName(name)
232 if len(tmp)<1:
233 if optional:
234 return None
235 else:
236 error("Element",name,"does not exist")
237 if len(tmp)>1:
238 error("More than one element",name,"does exist")
239 return tmp[0]
240
242 result="'type':'"+node.getAttribute("type")+"'"
243 para=self.expandVars(node.getAttribute("parameters"),args)
244 if para!="":
245 result+=","+para
246 return "{"+result+"}"
247
249 """Validate the arguments with the provided code (if it exists)"""
250 totalMsg=""
251 for a in self.argTree().getElementsByTagName("arg"):
252 msg=None
253 nm=a.getAttribute("name")
254 verify=self.getSingleElement(a,"verify",optional=True)
255 if verify:
256 valid=self.getSingleElement(verify,"validator",optional=True)
257 script=self.getSingleElement(verify,"script",optional=True)
258 if valid and script:
259 error("Variable",nm,"has script and validator. Only one of them supported")
260 elif valid:
261 typ=valid.getAttribute("type")
262 arg=args[nm]
263 isNumeric=False
264 if typ=="float":
265 isNumeric=True
266 try:
267 tmp=float(arg)
268 except ValueError:
269 msg="Not a floating point number"
270 elif typ=="integer":
271 isNumeric=True
272 try:
273 tmp=int(arg)
274 except ValueError:
275 msg="Not an integer number"
276 elif typ=="file":
277 if not path.exists(arg):
278 msg="File "+arg+" does not exist"
279 elif typ=="selection":
280 vals=valid.getAttribute("values").split("|")
281 if not arg in vals:
282 msg="Not in list of possible values: "+", ".join(vals)
283 elif typ=="vector":
284 tmp=FoamStringParser("a "+arg+";")
285 if type(tmp['a'])!=Vector:
286 msg="Is not a valid vector"
287 else:
288 error("No validator implemented for type",typ,"in variable",nm)
289 if isNumeric and not msg:
290 if valid.hasAttribute("min"):
291 if float(arg)<float(valid.getAttribute("min")):
292 msg="Must be bigger than "+valid.getAttribute("min")
293 if valid.hasAttribute("max"):
294 if float(arg)>float(valid.getAttribute("max")):
295 msg="Must be smaller than "+valid.getAttribute("max")
296
297 elif script:
298 if script.getAttribute("plugin")!="python":
299 error("Only plugin-type 'python' is supported for variable",nm)
300 code=script.firstChild.nodeValue
301 arg=args[nm]
302 exec code
303 if msg:
304 totalMsg+=nm+": "+msg+" "
305
306 if totalMsg=="":
307 totalMsg=None
308
309 return totalMsg
310
312 """Add derived variables to the argument dictionary"""
313
314 for _a_ in _args_:
315 exec "%s = '%s'" % (_a_,_args_[_a_])
316
317 if self.varTree():
318 for _a_ in self.varTree().getElementsByTagName("var"):
319 _nm_=_a_.getAttribute("name")
320 if _nm_ in ["_args_","_a_","_nm_"]:
321 error("Variable",_nm_,"is needed for this routine to work")
322
323 if len(_a_.firstChild.nodeValue)>0:
324 exec _a_.firstChild.nodeValue
325 exec "_args_['"+_nm_+"']=str("+_nm_+")"
326
327 return _args_
328
330 """Builds the case
331 @param cName: The name of the case directory
332 @param args: The arguments (as a dictionary)"""
333
334 args=self.calculateVariables(args)
335
336 os.mkdir(cName)
337
338 for d in self.parameterTree().getElementsByTagName("directory"):
339 dName=path.join(cName,d.getAttribute("name"))
340 if not path.isdir(dName):
341 os.mkdir(dName)
342 sName=path.join(self.templatePath(),d.getAttribute("name"))
343 for f in d.getElementsByTagName("file"):
344 dFile=path.join(dName,f.getAttribute("name"))
345 shutil.copy(path.join(sName,f.getAttribute("name")),dFile)
346 if len(f.getElementsByTagName("parameter"))>0:
347 pf=ParsedParameterFile(dFile)
348 for p in f.getElementsByTagName("parameter"):
349 pName=p.getAttribute("name")
350 pValue=self.expandVars(p.getAttribute("value"),args)
351 exec "pf"+pName+"="+pValue
352 pf.writeFile()
353
354 prep=self.getSingleElement(self.doc,"meshpreparation")
355 util=prep.getElementsByTagName("utility")
356 copy=self.getSingleElement(prep,"copy",optional=True)
357
358 if len(util)>0 and copy:
359 error("Copy and utilitiy mesh preparation specified")
360 elif len(util)>0:
361 for u in util:
362 app=u.getAttribute("command")
363 arg=self.expandVars(u.getAttribute("arguments"),args)
364 argv=[app,"-case",cName]+arg.split()
365 if oldApp():
366 argv[1]="."
367 run=BasicRunner(argv=argv,silent=True,logname="CaseBuilder.prepareMesh."+app)
368 run.start()
369 if not run.runOK():
370 error(app,"failed. Check the logs")
371 elif copy:
372 source=self.expandVars(copy.getAttribute("template"),args)
373 time=self.expandVars(copy.getAttribute("time"),args)
374 if time=="":
375 time="constant"
376 shutil.copytree(path.join(source,time,"polyMesh"),
377 path.join(cName,"constant","polyMesh"))
378 else:
379 error("Neither copy nor utilitiy mesh preparation specified")
380
381 dName=path.join(cName,self.initialDir())
382 if not path.isdir(dName):
383 os.mkdir(dName)
384 sName=path.join(self.templatePath(),self.initialDir())
385 for f in self.fieldTree().getElementsByTagName("field"):
386 dFile=path.join(dName,f.getAttribute("name"))
387 shutil.copy(path.join(sName,f.getAttribute("name")),dFile)
388 default=self.makeBC(self.getSingleElement(f,"defaultbc"),args)
389
390 CreateBoundaryPatches(args=["--fix-types",
391 "--overwrite",
392 "--clear",
393 "--default="+default,
394 dFile])
395 bcDict={}
396 bounds=self.boundaries()
397 for b in f.getElementsByTagName("bc"):
398 nm=b.getAttribute("name")
399 if nm not in bounds:
400 error("Boundary",nm,"not in list",bounds,"for field",f.getAttribute("name"))
401 bcDict[nm]=b
402
403 for name,pattern in self.boundaryPatterns():
404 if name in bcDict:
405 default=self.makeBC(bcDict[name],args)
406 CreateBoundaryPatches(args=["--filter="+pattern,
407 "--overwrite",
408 "--default="+default,
409 dFile])
410
411 ic=self.expandVars(self.getSingleElement(f,"ic").getAttribute("value"),args)
412 pf=ParsedParameterFile(dFile)
413 pf["internalField"]="uniform "+ic
414 pf.writeFile()
415