Source code for PyFoam.Applications.CaseBuilderBackend

"""
Represents the actual CaseBuilder-File and other things that have to do with the Casebuilder
"""

from xml.dom.minidom import parse
from os import path
import os
import shutil
import glob

from PyFoam.Error import error
from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,FoamStringParser
from PyFoam.Execution.BasicRunner import BasicRunner
from PyFoam.FoamInformation import oldAppConvention as oldApp
from .CreateBoundaryPatches import CreateBoundaryPatches
from PyFoam import configuration as config
from PyFoam.Basics.DataStructures import Vector

from PyFoam.ThirdParty.six import exec_

[docs]class CaseBuilderDescriptionList(object): """Gets a list of the case-builder files found in the current path""" def __init__(self): dirList=config().get("CaseBuilder","descriptionpath") self.list=[] for d in dirList: for f in glob.glob(path.join(d,"*.pfcb")): nm=path.basename(f) cb=CaseBuilderFile(f) self.list.append((nm,f,cb.name(),cb.description())) def __iter__(self): for f in self.list: yield f def __len__(self): return len(self.list) def __getitem__(self,i): return self.list[i]
[docs]class ArgWrapper(object): """Wraps the argument element for convenient access""" def __init__(self,el): self.el=el def __getattr__(self,name): if name=="type": tmp=self.el.getElementsByTagName("verify") if len(tmp)!=1: return None val=tmp[0].getElementsByTagName("validator") if len(val)!=1: return None else: return val[0].getAttribute("type") elif name=="values": tmp=self.el.getElementsByTagName("verify") if len(tmp)!=1: return None val=tmp[0].getElementsByTagName("validator") if len(val)!=1: return None else: return list(map(str,val[0].getAttribute("values").split("|"))) else: return self.el.getAttribute(name)
[docs]class CaseBuilderFile(object): """ This class reads an XML-file that describes how to build a case and gives information about the case and if asked to builds the actual case """ def __init__(self,fName): """:param fName: the XML-file that describes how to build the case""" dom=parse(fName) self.doc=dom.documentElement if self.doc.tagName!='casebuilder': error("Wrong root-element",self.doc.tagName,"Expected: 'casebuilder'")
[docs] def name(self): return self.doc.getAttribute("name")
[docs] def description(self): return self.doc.getAttribute("description")
[docs] def helpText(self): ht=self.getSingleElement(self.doc,"helptext",optional=True) if ht: return ht.firstChild.nodeValue else: return "<No help text>"
[docs] def argTree(self): return self.getSingleElement(self.doc,"arguments")
[docs] def varTree(self): return self.getSingleElement(self.doc,"variables",optional=True)
[docs] def filesTree(self): return self.getSingleElement(self.doc,"files")
[docs] def boundaryTree(self): return self.getSingleElement(self.filesTree(),"boundaries")
[docs] def fieldTree(self): return self.getSingleElement(self.filesTree(),"fieldfiles")
[docs] def parameterTree(self): return self.getSingleElement(self.filesTree(),"parameterfiles")
[docs] def templatePath(self): return self.expandVars(self.doc.getAttribute("template"))
[docs] def initialDir(self): tmp=self.doc.getAttribute("initialdir") if tmp=="": tmp="0" return tmp
[docs] def expandVars(self,orig,keys=None): orig=path.expanduser(orig) orig=path.expandvars(orig) if keys!=None: orig=orig % keys return orig
[docs] def boundaries(self): bounds=[] for a in self.boundaryTree().getElementsByTagName("boundary"): bounds.append(a.getAttribute("name")) return bounds
[docs] def boundaryPatterns(self): bounds=[] for a in self.boundaryTree().getElementsByTagName("boundary"): bounds.append((a.getAttribute("name"),a.getAttribute("pattern"))) return bounds
[docs] def boundaryPatternDict(self): res={} for nm,pat in self.boundaryPatterns(): res[nm]=pat return res
[docs] def boundaryDescriptions(self): bounds={} for a in self.boundaryTree().getElementsByTagName("boundary"): bounds[a.getAttribute("name")]=a.getAttribute("description") return bounds
[docs] def argumentGroups(self): args=[] for a in self.argTree().getElementsByTagName("argumentgroup"): args.append(a.getAttribute("name")) return args
[docs] def argumentGroupDescription(self): args={} for a in self.argTree().getElementsByTagName("argumentgroup"): args[a.getAttribute("name")]=a.getAttribute("description") return args
[docs] def arguments(self): args=[] for a in self.argTree().getElementsByTagName("arg"): args.append(a.getAttribute("name")) return args
[docs] def argumentDict(self): args={} for a in self.argTree().getElementsByTagName("arg"): args[a.getAttribute("name")]=ArgWrapper(a) return args
[docs] def groupArguments(self,name=None): """Returns a list with the arguments belongin to a specific group :param name: Name of the group. If none is given, then all the arguments belonging to no group are returned""" result=[] for c in self.argTree().childNodes: if "tagName" in dir(c): if c.tagName=="arg" and name==None: result.append(c.getAttribute("name")) elif c.tagName=="argumentgroup": if c.getAttribute("name")==name: for e in c.getElementsByTagName("arg"): result.append(e.getAttribute("name")) return result
[docs] def argumentDescriptions(self): args={} for a in self.argTree().getElementsByTagName("arg"): args[a.getAttribute("name")]=a.getAttribute("description") return args
[docs] def argumentDefaults(self): args={} for a in self.argTree().getElementsByTagName("arg"): args[a.getAttribute("name")]=a.getAttribute("default") return args
[docs] def getSingleElement(self,parent,name,optional=False): """Get an element and check that it is the only one :param parent: the parent element :param name: The name of the element""" tmp=parent.getElementsByTagName(name) if len(tmp)<1: if optional: return None else: error("Element",name,"does not exist") if len(tmp)>1: error("More than one element",name,"does exist") return tmp[0]
[docs] def makeBC(self,node,args): result="'type':'"+node.getAttribute("type")+"'" para=self.expandVars(node.getAttribute("parameters"),args) if para!="": result+=","+para return "{"+result+"}"
[docs] def verifyArguments(self,args): """Validate the arguments with the provided code (if it exists)""" totalMsg="" for a in self.argTree().getElementsByTagName("arg"): msg=None nm=a.getAttribute("name") verify=self.getSingleElement(a,"verify",optional=True) if verify: valid=self.getSingleElement(verify,"validator",optional=True) script=self.getSingleElement(verify,"script",optional=True) if valid and script: error("Variable",nm,"has script and validator. Only one of them supported") elif valid: typ=valid.getAttribute("type") arg=args[nm] isNumeric=False if typ=="float": isNumeric=True try: tmp=float(arg) except ValueError: msg="Not a floating point number" elif typ=="integer": isNumeric=True try: tmp=int(arg) except ValueError: msg="Not an integer number" elif typ=="file": if not path.exists(arg): msg="File "+arg+" does not exist" elif typ=="selection": vals=valid.getAttribute("values").split("|") if not arg in vals: msg="Not in list of possible values: "+", ".join(vals) elif typ=="vector": tmp=FoamStringParser("a "+arg+";") if type(tmp['a'])!=Vector: msg="Is not a valid vector" else: error("No validator implemented for type",typ,"in variable",nm) if isNumeric and not msg: if valid.hasAttribute("min"): if float(arg)<float(valid.getAttribute("min")): msg="Must be bigger than "+valid.getAttribute("min") if valid.hasAttribute("max"): if float(arg)>float(valid.getAttribute("max")): msg="Must be smaller than "+valid.getAttribute("max") elif script: if script.getAttribute("plugin")!="python": error("Only plugin-type 'python' is supported for variable",nm) code=script.firstChild.nodeValue arg=args[nm] exec_(code) if msg: totalMsg+=nm+": "+msg+" " if totalMsg=="": totalMsg=None return totalMsg
[docs] def calculateVariables(self,_args_): """Add derived variables to the argument dictionary""" for _a_ in _args_: exec_("%s = '%s'" % (_a_,_args_[_a_])) if self.varTree(): for _a_ in self.varTree().getElementsByTagName("var"): _nm_=_a_.getAttribute("name") if _nm_ in ["_args_","_a_","_nm_"]: error("Variable",_nm_,"is needed for this routine to work") if len(_a_.firstChild.nodeValue)>0: exec_(_a_.firstChild.nodeValue) exec_("_args_['"+_nm_+"']=str("+_nm_+")") return _args_
[docs] def buildCase(self,cName,args): """Builds the case :param cName: The name of the case directory :param args: The arguments (as a dictionary)""" args=self.calculateVariables(args) os.mkdir(cName) for d in self.parameterTree().getElementsByTagName("directory"): dName=path.join(cName,d.getAttribute("name")) if not path.isdir(dName): os.mkdir(dName) sName=path.join(self.templatePath(),d.getAttribute("name")) for f in d.getElementsByTagName("file"): dFile=path.join(dName,f.getAttribute("name")) shutil.copy(path.join(sName,f.getAttribute("name")),dFile) if len(f.getElementsByTagName("parameter"))>0: pf=ParsedParameterFile(dFile) for p in f.getElementsByTagName("parameter"): pName=p.getAttribute("name") pValue=self.expandVars(p.getAttribute("value"),args) exec_("pf"+pName+"="+pValue) pf.writeFile() prep=self.getSingleElement(self.doc,"meshpreparation") util=prep.getElementsByTagName("utility") copy=self.getSingleElement(prep,"copy",optional=True) if len(util)>0 and copy: error("Copy and utilitiy mesh preparation specified") elif len(util)>0: for u in util: app=u.getAttribute("command") arg=self.expandVars(u.getAttribute("arguments"),args) argv=[app,"-case",cName]+arg.split() if oldApp(): argv[1]="." run=BasicRunner(argv=argv,silent=True,logname="CaseBuilder.prepareMesh."+app) run.start() if not run.runOK(): error(app,"failed. Check the logs") elif copy: source=self.expandVars(copy.getAttribute("template"),args) time=self.expandVars(copy.getAttribute("time"),args) if time=="": time="constant" shutil.copytree(path.join(source,time,"polyMesh"), path.join(cName,"constant","polyMesh")) else: error("Neither copy nor utilitiy mesh preparation specified") dName=path.join(cName,self.initialDir()) if not path.isdir(dName): os.mkdir(dName) sName=path.join(self.templatePath(),self.initialDir()) for f in self.fieldTree().getElementsByTagName("field"): dFile=path.join(dName,f.getAttribute("name")) shutil.copy(path.join(sName,f.getAttribute("name")),dFile) default=self.makeBC(self.getSingleElement(f,"defaultbc"),args) CreateBoundaryPatches(args=["--fix-types", "--overwrite", "--clear", "--default="+default, dFile]) bcDict={} bounds=self.boundaries() for b in f.getElementsByTagName("bc"): nm=b.getAttribute("name") if nm not in bounds: error("Boundary",nm,"not in list",bounds,"for field",f.getAttribute("name")) bcDict[nm]=b for name,pattern in self.boundaryPatterns(): if name in bcDict: default=self.makeBC(bcDict[name],args) CreateBoundaryPatches(args=["--filter="+pattern, "--overwrite", "--default="+default, dFile]) ic=self.expandVars(self.getSingleElement(f,"ic").getAttribute("value"),args) pf=ParsedParameterFile(dFile) pf["internalField"]="uniform "+ic pf.writeFile()
# Should work with Python3 and Python2