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  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   
21 -class CaseBuilderDescriptionList(object):
22 """Gets a list of the case-builder files found in the current path"""
23 - def __init__(self):
24 dirList=config().get("CaseBuilder","descriptionpath") 25 self.list=[] 26 for d in dirList: 27 for f in glob.glob(path.join(d,"*.pfcb")): 28 nm=path.basename(f) 29 cb=CaseBuilderFile(f) 30 self.list.append((nm,f,cb.name(),cb.description()))
31
32 - def __iter__(self):
33 for f in self.list: 34 yield f
35
36 - def __len__(self):
37 return len(self.list)
38
39 - def __getitem__(self,i):
40 return self.list[i]
41
42 -class ArgWrapper(object):
43 """Wraps the argument element for convenient access"""
44 - def __init__(self,el):
45 self.el=el
46
47 - def __getattr__(self,name):
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
69 -class CaseBuilderFile(object):
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
75 - def __init__(self,fName):
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
84 - def name(self):
85 return self.doc.getAttribute("name")
86
87 - def description(self):
88 return self.doc.getAttribute("description")
89
90 - def helpText(self):
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
97 - def argTree(self):
98 return self.getSingleElement(self.doc,"arguments")
99
100 - def varTree(self):
101 return self.getSingleElement(self.doc,"variables",optional=True)
102
103 - def filesTree(self):
104 return self.getSingleElement(self.doc,"files")
105
106 - def boundaryTree(self):
107 return self.getSingleElement(self.filesTree(),"boundaries")
108
109 - def fieldTree(self):
110 return self.getSingleElement(self.filesTree(),"fieldfiles")
111
112 - def parameterTree(self):
113 return self.getSingleElement(self.filesTree(),"parameterfiles")
114
115 - def templatePath(self):
116 return self.expandVars(self.doc.getAttribute("template"))
117
118 - def initialDir(self):
119 tmp=self.doc.getAttribute("initialdir") 120 if tmp=="": 121 tmp="0" 122 return tmp
123
124 - def expandVars(self,orig,keys=None):
125 orig=path.expanduser(orig) 126 orig=path.expandvars(orig) 127 if keys!=None: 128 orig=orig % keys 129 return orig
130
131 - def boundaries(self):
132 bounds=[] 133 134 for a in self.boundaryTree().getElementsByTagName("boundary"): 135 bounds.append(a.getAttribute("name")) 136 137 return bounds
138
139 - def boundaryPatterns(self):
140 bounds=[] 141 142 for a in self.boundaryTree().getElementsByTagName("boundary"): 143 bounds.append((a.getAttribute("name"),a.getAttribute("pattern"))) 144 145 return bounds
146
147 - def boundaryPatternDict(self):
148 res={} 149 for nm,pat in self.boundaryPatterns(): 150 res[nm]=pat 151 return res
152
153 - def boundaryDescriptions(self):
154 bounds={} 155 156 for a in self.boundaryTree().getElementsByTagName("boundary"): 157 bounds[a.getAttribute("name")]=a.getAttribute("description") 158 159 return bounds
160
161 - def argumentGroups(self):
162 args=[] 163 164 for a in self.argTree().getElementsByTagName("argumentgroup"): 165 args.append(a.getAttribute("name")) 166 167 return args
168
169 - def argumentGroupDescription(self):
170 args={} 171 172 for a in self.argTree().getElementsByTagName("argumentgroup"): 173 args[a.getAttribute("name")]=a.getAttribute("description") 174 175 return args
176
177 - def arguments(self):
178 args=[] 179 180 for a in self.argTree().getElementsByTagName("arg"): 181 args.append(a.getAttribute("name")) 182 183 return args
184
185 - def argumentDict(self):
186 args={} 187 188 for a in self.argTree().getElementsByTagName("arg"): 189 args[a.getAttribute("name")]=ArgWrapper(a) 190 191 return args
192
193 - def groupArguments(self,name=None):
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
211 - def argumentDescriptions(self):
212 args={} 213 214 for a in self.argTree().getElementsByTagName("arg"): 215 args[a.getAttribute("name")]=a.getAttribute("description") 216 217 return args
218
219 - def argumentDefaults(self):
220 args={} 221 222 for a in self.argTree().getElementsByTagName("arg"): 223 args[a.getAttribute("name")]=a.getAttribute("default") 224 225 return args
226
227 - def getSingleElement(self,parent,name,optional=False):
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
242 - def makeBC(self,node,args):
243 result="'type':'"+node.getAttribute("type")+"'" 244 para=self.expandVars(node.getAttribute("parameters"),args) 245 if para!="": 246 result+=","+para 247 return "{"+result+"}"
248
249 - def verifyArguments(self,args):
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
312 - def calculateVariables(self,_args_):
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
330 - def buildCase(self,cName,args):
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 # Should work with Python3 and Python2 418