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