Package PyFoam :: Package Applications :: Module CaseBuilderBackend
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.CaseBuilderBackend

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