Source code for PyFoam.Applications.PrepareCase

"""
Application-class that implements pyFoamPrepareCase.py
"""
from optparse import OptionGroup

from .PyFoamApplication import PyFoamApplication

from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory
from PyFoam.Basics.DataStructures import DictProxy
from PyFoam.Basics.Utilities import rmtree,copytree,execute,remove,find
from PyFoam.RunDictionary.ParsedParameterFile import ParsedParameterFile,WriteParameterFile,FoamStringParser
from PyFoam.Basics.TemplateFile import TemplateFile
from PyFoam.Execution.BasicRunner import BasicRunner
from PyFoam.Basics.RestructuredTextHelper import RestructuredTextHelper

from PyFoam.FoamInformation import foamFork,foamVersion

from .CommonTemplateFormat import CommonTemplateFormat
from .CommonTemplateBehaviour import CommonTemplateBehaviour

from PyFoam.ThirdParty.six import print_,iteritems,exec_

from PyFoam import configuration

from os import path,listdir,mkdir
from shutil import copymode,copy,move
from collections import OrderedDict
import time
import re

from .CursesApplicationWrapper import addExpr

prepareExpr=[r'^Executing',
             r'^Looking for',
             r'^Skipping',
             r'^Found template']

for e in prepareExpr:
    addExpr(e)

[docs]def buildFilenameExtension(paraList,valueStrings): ext="" if len(paraList)>0: ext="_".join([path.basename(p) for p in paraList]) if len(valueStrings)>0: d={} for v in valueStrings: d.update(eval(v)) ext+="_"+"_".join(["%s=%s" % (n,str(v)) for n,v in iteritems(d)]) if ext=="": return "_vanilla" else: return "_"+ext
[docs]class PrepareCase(PyFoamApplication, CommonTemplateBehaviour, CommonTemplateFormat): parameterOutFile="PyFoamPrepareCaseParameters" def __init__(self, args=None, exactNr=True, interspersed=True, usage="%prog <caseDirectory>", examples=None, nr=1, description=None, **kwargs): self.defaultClearCase=configuration().get("PrepareCase","ClearCaseScript") self.defaultMeshCreate=configuration().get("PrepareCase","MeshCreateScript") self.defaultPostCopy=configuration().get("PrepareCase","PostCopyScript") self.defaultCaseSetup=configuration().get("PrepareCase","CaseSetupScript") self.defaultDecomposeMesh=configuration().get("PrepareCase","DecomposeMeshScript") self.defaultDecomposeFields=configuration().get("PrepareCase","DecomposeFieldsScript") self.defaultDecomposeCase=configuration().get("PrepareCase","DecomposeCaseScript") self.defaultParameterFile=configuration().get("PrepareCase","DefaultParameterFile") self.defaultIgnoreDirecotries=configuration().getList("PrepareCase","IgnoreDirectories") description2="""\ Prepares a case for running. This is intended to be the replacement for boiler-plate scripts. The steps done are 1. Read parameters from default.parameters (if present) and parameter files and parameters specified on the command line 2. Execute a script derviedParamters.py to calculate new values 3. Clear old data from the case (including processor directories). If present uses script clearCase.sh 4. if a folder 0.org or 0.orig is present remove the 0 folder too 5. go through all folders and for every found file with the extension .template do template expansion using the pyratemp-engine (automatically create variables casePath and caseName) 6. create a mesh (either by using a script or if a blockMeshDict is present by running blockMesh. If none of these is present assume that there is a valid mesh present). Afterwards (if present) a script decomposeMesh.sh is executed 7. copy every foo.org that is found to to foo (recursively if directory). 8. If present exectute a script postCopy.sh 9. If present (and if a parallel run) a script decomposeFields.sh is executed 10. do template-expansion for every file with the extension .postTemplate 11. execute another preparation script (caseSetup.sh). If no such script is found but a setFieldsDict in system then setFields is executed. Afterwards (if present) a script decomposeCase.sh is executed 12. do final template-expansion for every file with the extension .finalTemplate The used parameters are written to a file 'PyFoamPrepareCaseParameters' and are used by other utilities """ examples2="""\ %prog . --paramter-file=parameters.base Prepare the current case with the parameters list in parameters.base %prog . --paramter-file=parameters.base --values-string="{'visco':1e-3}" Changes the value of the parameter visco %prog . --no-mesh-create Skip the mesh creation phase %prog exampleCase --paramter-file=parameters.base --build-example --clone-case=originalCase Build a case named exampleCase from the case originalCase using the parameter file parameter.base (creates an Allrun-script ) """ PyFoamApplication.__init__(self, args=args, description=description if description else description2, usage=usage, examples=examples if examples else examples2, interspersed=interspersed, nr=nr, exactNr=exactNr, findLocalConfigurationFile=self.localConfigInArgs, **kwargs)
[docs] def addOptions(self): output=OptionGroup(self.parser, "Output", "What information should be given") self.parser.add_option_group(output) output.add_option("--fatal", action="store_true", dest="fatal", default=False, help="If non-cases are specified the program should abort") output.add_option("--no-complain", action="store_true", dest="noComplain", default=False, help="Don't complain about non-case-files") output.add_option("--quiet", action="store_false", dest="verbose", default=True, help="Do not report what is being done") output.add_option("--no-write-parameters", action="store_false", dest="writeParameters", default=True, help="Usually a file '"+self.parameterOutFile+"' with a dictionary of the used parameters is written to the case directory. ") output.add_option("--no-write-report", action="store_false", dest="writeReport", default=True, help="Usually a file '"+self.parameterOutFile+".rst' with a ReST-file that reports the used parameters is written to the case directory. ") output.add_option("--warn-on-wrong-options", action="store_false", dest="failOnWrongOption", default=True, help="Only issue a warning if a value was set that is not found in the list of valid options") extensions=OptionGroup(self.parser, "Extensions", "File extensions that are used in actions") self.parser.add_option_group(extensions) extensions.add_option("--template-extension", action="store", dest="templateExt", default=".template", help="Extension for template files. Default: %default") extensions.add_option("--post-template-extension", action="store", dest="postTemplateExt", default=".postTemplate", help="Extension for post-template files. Default: %default") extensions.add_option("--final-template-extension", action="store", dest="finalTemplateExt", default=".finalTemplate", help="Extension for final-template files. Default: %default") extensions.add_option("--original-extension", action="store", dest="originalExt", default=".org", help="Extension for files and directories that are copied. Default: %default") extensions.add_option("--zero-time-original-extensions", action="append", dest="zeroTimeOriginalExtensions", default=[".orig"], help="Additional extensions to be used for the original of the zero time directory. The first one is used. Default: %default") extensions.add_option("--extension-addition", action="append", dest="extensionAddition", default=[], help="Addtional extension that is added to templates and originals to allow overrides. For instance if an addition 'steady' is specified and a file 'T.template' and 'T.template.steady' is found then the later is used. Can be specied more than once. The last instance is used.") inputs=OptionGroup(self.parser, "Inputs", "Inputs for the templating process") self.parser.add_option_group(inputs) inputs.add_option("--parameter-file", action="append", default=[], dest="valuesDicts", help="Name of a dictionary-file in OpenFOAM-format. Can be specified more than once. Values in later files override old values. If a file "+self.defaultParameterFile+" is present it is read before all other paraemter files") inputs.add_option("--no-default-parameter-file", action="store_false", default=True, dest="useDefaultParameterFile", help="Even if present do NOT use the file "+self.defaultParameterFile+" before the other parameter files") inputs.add_option("--values-string", action="append", default=[], dest="values", help="String with the values that are to be inserted into the template as a dictionaty in Python-format if the string starts with '{' and ends with '}'. Otherwise it is assumed that the string is a dictionary in OpenFOAM-format. Can be specified more than once and overrides values from the parameter-files") special=OptionGroup(self.parser, "Special files and directories", "Files and directories that get special treatment") self.parser.add_option_group(special) special.add_option("--directories-to-clean", action="append", default=["0"], dest="cleanDirectories", help="Directory from which templates are cleaned (to avoid problems with decomposePar). Can be specified more than once. Default: %default") special.add_option("--overload-directory", action="append", default=[], dest="overloadDirs", help="Before starting the preparation process load files from this directory recursively into this case. Caution: existing files will be overwritten. Can be specified more than once. Directories are then copied in the specified order") special.add_option("--clone-case", default=None, dest="cloneCase", help="If this is set then this directory is cloned to the specified directory and setup is done there (the target directory must not exist except if the name is build with --automatic-casename)") special.add_option("--automatic-casename", action="store_true", dest="autoCasename", default=False, help="If used with --clone-case then the casename is built from the original casename, the names of the parameter-files and the set values") special.add_option("--ignore-directories", action="append", dest="ignoreDirectories", default=list(self.defaultIgnoreDirecotries), help="Regular expression. Directories that match this expression are ignored. Can be used more than once. Already set: "+", ".join(["r'"+e+"'" for e in self.defaultIgnoreDirecotries])) CommonTemplateFormat.addOptions(self) CommonTemplateBehaviour.addOptions(self) mode=OptionGroup(self.parser, "Mode", "How the utility should work") self.parser.add_option_group(mode) mode.add_option("--execute-in-case-directory", action="store_true", dest="executeInCaseDirectory", default=False, help="Execute in the specified case directory. This means that paths to parameter files etc can be relative (or in) that directory") mode.add_option("--build-example", action="store_true", dest="buildExample", default=False, help="Build an example case that can be executed without pyFoam. Only evaluates the templates, builds a AllRun-script and removes unnecessary files. Does not work for all configurations") if configuration().getboolean("PrepareCase","ZipExtensionlessTemplateResults"): mode.add_option("--no-zip-extensionless-template-results", action="store_false", dest="zipExtensionlessTemplateResults", default=True, help="Do not automatically zip extensionless template results") else: mode.add_option("--zip-extensionless-template-results", action="store_true", dest="zipExtensionlessTemplateResults", default=False, help="Zip the results of template evaluations. So a template file foo.template gets written to a zipped file foo.gz. This is only done if foo has no extension") defaultZipableExtensions=configuration().getList("PrepareCase","ZipableExtensions") mode.add_option("--zipable-extensions", action="append", dest="zipableExtensions", default=list(defaultZipableExtensions), help="Template Results with these extensions are also zipped. Extensions have to include the '.' in the beginning. Already set: "+", ".join(["'"+e+"'" for e in defaultZipableExtensions])) stages=OptionGroup(self.parser, "Stages", "Which steps should be executed") self.parser.add_option_group(stages) stages.add_option("--only-variables", action="store_true", dest="onlyVariables", default=False, help="Do nothing. Only read the variables") stages.add_option("--no-clear", action="store_false", dest="doClear", default=True, help="Do not clear the case") stages.add_option("--keep-zero", action="store_true", dest="keepZero", default=False, help="Do not remove the 0 directory even if a 0.org (or equivalent) is there") stages.add_option("--no-templates", action="store_false", dest="doTemplates", default=True, help="Do not rework the templates") stages.add_option("--stop-after-templates", action="store_true", dest="stopAfterTemplates", default=False, help="Stop after the templates were done") stages.add_option("--no-mesh-create", action="store_false", dest="doMeshCreate", default=True, help="Do not execute a script to create a mesh") stages.add_option("--no-post-copy", action="store_false", dest="doPostCopy", default=True, help="Do not execute a script after the copying of 0.org") stages.add_option("--force-mesh-decompose", action="store_true", dest="doMeshDecompose", default=False, help="Execute the script for mesh decomposition even if the mesh has not been created") stages.add_option("--no-copy", action="store_false", dest="doCopy", default=True, help="Do not copy original directories") stages.add_option("--force-decompose-field", action="store_true", dest="doFieldDecompose", default=False, help="Execute a script to decompose the fields even if no originals were copied") stages.add_option("--no-post-templates", action="store_false", dest="doPostTemplates", default=True, help="Do not rework the post-templates") stages.add_option("--no-case-setup", action="store_false", dest="doCaseSetup", default=True, help="Do not execute a script to set initial conditions etc") stages.add_option("--force-case-decompose", action="store_true", dest="doCaseDecompose", default=False, help="Execute the script for case decomposition even if the case setup was not done") stages.add_option("--no-final-templates", action="store_false", dest="doFinalTemplates", default=True, help="Do not rework the final-templates") stages.add_option("--no-template-clean", action="store_false", dest="doTemplateClean", default=True, help="Do not clean template files from 0-directory") stages.add_option("--no-paraview-file", action="store_false", dest="paraviewFile", default=True, help="Do not create a .foam file that allows paraview to open the case") scripts=OptionGroup(self.parser, "Scripts", "Specification of scripts to be executed") self.parser.add_option_group(scripts) scripts.add_option("--case-clear-script", action="store", dest="clearCaseScript", default=None, help="Script that is executed in addition to the regular clearing of the case data. If not specified then the utility looks for "+self.defaultClearCase+" and executes this.") scripts.add_option("--additional-clear-case-scripts", action="append", dest="additionalClearCase", default=["Allclean"], help="Additional script names to try if no case clearing script is found. Can be used more than once Default: %default") scripts.add_option("--mesh-create-script", action="store", dest="meshCreateScript", default=None, help="Script that is executed after the template expansion to create the mesh. If not specified then the utility looks for "+self.defaultMeshCreate+" and executes this. If this is also not found blockMesh is executed if a blockMeshDict is found") scripts.add_option("--post-copy-script", action="store", dest="postCopyScript", default=None, help="Script that is executed after the 0.org directory was copied to 0. If not specified then the utility looks for "+self.defaultPostCopy+" and executes this.") scripts.add_option("--decompose-mesh-script", action="store", dest="decomposeMeshScript", default=None, help="Script that is executed after the mesh is created. If not specified then the utility looks for "+self.defaultDecomposeMesh+" and executes this.") scripts.add_option("--decompose-fields-script", action="store", dest="decomposeFieldsScript", default=None, help="Script that is executed after the mesh is created and decomposed. If not specified then the utility looks for "+self.defaultDecomposeFields+" and executes this") scripts.add_option("--additional-mesh-create-scripts", action="append", dest="additionalMeshCreate", default=["Allrun.pre","Allrun.mesh"], help="Additional script names to try if no mesh creation script is found. Can be used more than once Default: %default") stages.add_option("--no-keep-zero-directory-from-mesh-create", action="store_false", dest="keepZeroDirectoryFromMesh", default=True, help="If the script that creates the mesh generates a '0'-directory with data then this data will be removed. Otherwise it is kept") scripts.add_option("--case-setup-script", action="store", dest="caseSetupScript", default=None, help="Script that is executed after the original files have been copied to set initial conditions or similar. If not specified then the utility looks for "+self.defaultCaseSetup+" and executes this.") scripts.add_option("--decompose-case-script", action="store", dest="decomposeCaseScript", default=None, help="Script that is executed after the case setup is finished. If not specified then the utility looks for "+self.defaultDecomposeCase+" and executes this") scripts.add_option("--derived-parameters-script", action="store", dest="derivedParametersScript", default="derivedParameters.py", help="If this script is found then it is executed after the parameters are read. All variables set in this script can then be used in the templates. Default: %default") scripts.add_option("--allow-derived-changes", action="store_true", dest="allowDerivedChanges", default=False, help="Allow that the derived script changes existing values") scripts.add_option("--continue-on-script-failure", action="store_false", dest="failOnScriptFailure", default=True, help="Don't fail the whole process even if a script fails") variables=OptionGroup(self.parser, "Variables", "Variables that are automatically defined") self.parser.add_option_group(variables) variables.add_option("--number-of-processors", action="store", type=int, dest="numberOfProcessors", default=1, help="Value of the variable numberOfProcessors. Default: %default")
[docs] def info(self,*args): """Information output""" if self.opts.verbose: print_(*args)
[docs] def listdir(self,d,ext): """Private copy of listdir. Returns a list of pairs: first element is the real file-name. Second the name with the extensions stripped off or None if the file doesn't match any extensions""" extAdditions=[""]+["."+e for e in self.opts.extensionAddition] allFiles=listdir(d) result=[] templated=set() for f in allFiles: isPlain=True for e in extAdditions: ee=ext+e if len(f)>len(ee): if f[-len(ee):]==ee: isPlain=False templated.add(f[:-len(ee)]) if isPlain: result.append((f,None)) for t in templated: found=None for e in extAdditions: tt=t+ext+e if tt in allFiles: found=tt if found==None: self.error("This should not happen. Nothing found for",t,"with extensions", extAdditions,"in files",allFiles) else: result.append((found,t)) return result
[docs] def copyOriginals(self,startDir,extension=None,recursive=True): """Go recursivly through directories and copy foo.org to foo""" self.info("Looking for originals in",startDir) if extension is None: extension=self.opts.originalExt for f,t in self.listdir(startDir,extension): if f[0]==".": self.info("Skipping",f) continue src=path.join(startDir,f) if t!=None: dst=path.join(startDir,t) if path.exists(dst): self.info("Replacing",dst,"with",src) rmtree(dst) else: self.info("Copying",src,"to",dst) copytree(src,dst,force=True) elif path.isdir(src) and recursive: self.copyOriginals(src, extension=extension, recursive=recursive)
[docs] def cleanExtension(self, startDir, ext): """Go recursivly through directories and remove all files that have a specific extension""" self.info("Looking for extension",ext,"in",startDir) for f in listdir(startDir): if f[0]==".": self.info("Skipping",f) continue src=path.join(startDir,f) if path.splitext(src)[1]==ext or path.splitext(path.splitext(src)[0])[1]==ext: if not path.isdir(src): self.info("Removing",src) remove(src) if path.isdir(src): self.cleanExtension(src,ext)
[docs] def searchAndReplaceTemplates(self, startDir, values, templateExt, ignoreDirectories=[]): """Go through the directory recursively and replate foo.template with foo after inserting the values""" self.info("Looking for templates with extension",templateExt,"in ",startDir) for f,t in self.listdir(startDir,templateExt): if f[0]==".": self.info("Skipping",f) continue if path.isdir(path.join(startDir,f)): matches=None for p in ignoreDirectories: if re.compile(p+"$").match(f): matches=p break if matches: self.info("Skipping directory",f,"because it matches",matches) continue self.searchAndReplaceTemplates( path.join(startDir,f), values, templateExt) elif t!=None: tName=path.join(startDir,t) fName=path.join(startDir,f) self.info("Found template for",tName) t=TemplateFile(name=fName, tolerantRender=self.opts.tolerantRender, allowExec=self.opts.allowExec or configuration().getboolean("Template","AllowExecution"), expressionDelimiter=self.opts.expressionDelimiter, assignmentDebug=self.pickAssignmentDebug(fName), assignmentLineStart=self.opts.assignmentLineStart) ext = path.splitext(tName)[1] if self.opts.zipExtensionlessTemplateResults and (ext == "" or ext in self.opts.zipableExtensions): gzip = True else: gzip = False written = t.writeToFile(tName, values, gzip=gzip) copymode(fName, written)
[docs] def overloadDir(self,here,there): """Copy files recursively. Overwrite local copies if they exist""" for f in listdir(there): fSrc=path.join(there,f) fDst=path.join(here,f) if path.isdir(fSrc): if not path.exists(fDst): self.info("Creating directory",fDst) mkdir(fDst) elif not path.isdir(fDst): self.error("Destination path",fDst,"exists, but is no directory") self.overloadDir(fDst,fSrc) elif path.isfile(fSrc): isThere=False rmDest=None if path.exists(fDst): isThere=True elif path.splitext(fSrc)[1]==".gz" and \ path.exists(path.splitext(fDst)[0]): rmDest=path.splitext(fDst)[0] elif path.splitext(fSrc)[1]=="" and \ path.exists(fDst+".gz"): rmDest=fDst+".gz" if rmDest: remove(rmDest) if isThere: if not path.isfile(fDst): self.error("Desination",fDst,"exists but is no file") self.info("Copying",fSrc,"to",fDst) copy(fSrc,fDst) else: self.error("Source file",fSrc,"is neither file nor directory")
[docs] def run(self): cName=self.parser.getArgs()[0] if self.opts.buildExample and not self.opts.cloneCase: self.error("For --build-example the option --clone-case is necessary") if self.opts.buildExample: # self.opts.writeParameters=False # self.opts.writeReport=False pass if self.opts.cloneCase: if self.opts.autoCasename: cName=path.join(cName, path.basename(self.opts.cloneCase)+ buildFilenameExtension(self.opts.valuesDicts, self.opts.values)) if path.exists(cName): self.error(cName,"already existing (case should not exist when used with --clone-case)") if self.checkCase(self.opts.cloneCase, fatal=self.opts.fatal, verbose=not self.opts.noComplain): self.addLocalConfig(self.opts.cloneCase) orig=SolutionDirectory(self.opts.cloneCase, archive=None,paraviewLink=False) sol=orig.cloneCase(cName, paraviewLink=self.opts.paraviewFile) else: if self.checkCase(cName, fatal=self.opts.fatal, verbose=not self.opts.noComplain): self.addLocalConfig(cName) sol=SolutionDirectory(cName,archive=None, parallel=True, paraviewLink=self.opts.paraviewFile) previousDirectory = None if self.opts.executeInCaseDirectory: previousDirectory = path.abspath(path.curdir) from os import chdir if path.realpath(cName)==path.realpath(path.curdir): self.warning("Not changing directory because Already in",path.realpath(path.curdir)) else: chdir(path.realpath(cName)) cName=path.curdir try: self.__lastMessage=None self.prepare(sol,cName=cName) except: if self.__lastMessage: self.__writeToStateFile(sol,self.__lastMessage+" failed") raise if previousDirectory: # Change back if this is used in a script chdir(previousDirectory)
def __strip(self,val): """Strip extra " from strings""" if isinstance(val,(str,)): if len(val)>2: if val[0]=='"' and val[-1]=='"': return val[1:-1] return val
[docs] def processDefault(self,raw): """Process a dictionary and return a 'flattened' dictionary with the values and a dictionary with the meta-data""" values=OrderedDict() meta=OrderedDict() meta[""]={} for k,v in iteritems(raw): isNormal=True if isinstance(v,(DictProxy,dict)): if "description" in v: if "default" in v: if "values" in v: self.warning(k+" has also a 'values'-entry. Might be a subgroup") vMeta={} for a in v: if a=="description": vMeta[a]=self.__strip(v[a]) else: vMeta[a]=v[a] meta[""][k]=vMeta elif "values" in v: isNormal=False if isNormal: if k in values: self.error(k,"defined twice in defaults") if not k in meta[""]: meta[""][k]={"default":v} values[k]=v else: values[k]=meta[""][k]["default"] else: pVal,pMeta=self.processDefault(v["values"]) meta[k]=(self.__strip(v["description"]),pMeta) for a in pVal: if a in values: self.error(a,"already defined in sub-directory") else: values[a]=pVal[a] return values,meta
[docs] def getDefaultValues(self,cName): """Process the file with the default values - if present Returns a dictionary with the values and a dictionary with the meta-data about the parameters""" defFile=path.join(path.abspath(cName),self.defaultParameterFile) if self.opts.useDefaultParameterFile and path.exists(defFile): self.info("Using default values from",defFile) return self.processDefault( ParsedParameterFile(defFile, noHeader=True, doMacroExpansion=True).getValueDict()) else: return {},{}
[docs] def addDictValues(self,name,description,values): """Add values from a dictionary""" meta=dict([(k,{"default":v}) for k,v in iteritems(values)]) self.metaData[name]=(description,{"":meta}) return values
[docs] def makeReport(self,values,level=2,meta=None): if meta is None: meta=self.metaData helper=RestructuredTextHelper(defaultHeading=level) val="" for k in meta: if k=="": if len(meta[k])==0: continue tab=helper.table(labeled=True) for kk in meta[k]: if "default" in meta[k][kk] and values[kk]!=meta[k][kk]["default"]: changed=True tab.addRow(helper.strong(kk)) else: changed=False tab.addRow(kk) for a,v in iteritems(meta[k][kk]): tab.addItem(a,v) if changed: tab.addItem("Value",helper.strong(values[kk])) else: tab.addItem("Value",values[kk]) val+=str(tab) else: descr,newMeta=meta[k] val+=helper.heading(descr) val+="\nShort name: "+helper.literal(k)+"\n" val+=self.makeReport(values, level=level+1, meta=newMeta) return val
[docs] def checkCorrectOptions(self,values,meta=None): if meta is None: meta=self.metaData for k in meta: if k=="": for kk in meta[k]: if "options" in meta[k][kk] and values[kk] not in meta[k][kk]["options"]: if self.opts.failOnWrongOption: func=self.error else: func=self.warning func("Value",values[kk],"for parameter",kk, "not in listv of allowed options:", ", ".join([str(v) for v in meta[k][kk]["options"]])) else: self.checkCorrectOptions(values,meta[k][1])
[docs] def executeScript(self, scriptName, workdir, echo, allrun=None): """Execute a script and write a corresponding logfile""" if allrun: allrun.write("\nrunApplication "+ path.join(path.curdir,path.basename(scriptName))+ "\n") return import sys,os,shutil scriptRun=scriptName if sys.platform in ["darwin"]: scriptRun=path.join(path.dirname(scriptName), "runOnMacVersionOf_"+path.basename(scriptName)) with open(scriptName) as i: with open(scriptRun,"w") as o: o.write(i.readline()) o.write("\n# Necessary because Mac OS X does not pass this variable\n") o.write("export LD_LIBRARY_PATH="+os.environ["LD_LIBRARY_PATH"]+"\n\n") o.write(i.read()) shutil.copymode(scriptName,scriptRun) self.warning("Executing modified script",scriptRun, "instead of",scriptName) with open(scriptName+".log","w") as outfile: ret,txt=execute([scriptRun], workdir=workdir, echo=echo, outfile=outfile, getReturnCode=True) if ret not in [0,None]: self.info(scriptName,"failed with code",ret) if self.opts.failOnScriptFailure: self.error("Script",scriptName,"failed with code",ret)
def __writeToStateFile(self,sol,message): """Write a message to a state file""" self.__lastMessage=message open(path.join(sol.name,"PyFoamState.TheState"),"w").write("Prepare: "+message+"\n")
[docs] def prepare(self,sol, cName=None, overrideParameters=None, numberOfProcessors=None): """Do the actual preparing :param numberOfProcessors: If set this overrides the value set in the command line""" didDecompose=False if cName==None: cName=sol.name if self.opts.onlyVariables: self.opts.verbose=True vals={} vals,self.metaData=self.getDefaultValues(cName) vals.update(self.addDictValues("System", "Automatically defined values", { "casePath" : '"'+path.abspath(cName)+'"', "caseName" : '"'+path.basename(path.abspath(cName))+'"', "foamVersion" : foamVersion(), "foamFork" : foamFork(), "numberOfProcessors" : numberOfProcessors if numberOfProcessors!=None else self.opts.numberOfProcessors })) if len(self.opts.extensionAddition)>0: vals.update(self.addDictValues("ExtensionAdditions", "Additional extensions to be processed", dict((e,True) for e in self.opts.extensionAddition))) valsWithDefaults=set(vals.keys()) self.info("Looking for template values",cName) for f in self.opts.valuesDicts: self.info("Reading values from",f) vals.update(ParsedParameterFile(f, noHeader=True, doMacroExpansion=True).getValueDict()) setValues={} for v in self.opts.values: v=v.strip() self.info("Updating values",v) if v[0]=="{" and v[-1]=="}": newValues=eval(v) else: newValues=FoamStringParser(v).data vals.update(newValues) setValues.update(newValues) if overrideParameters: vals.update(overrideParameters) unknownValues=set(vals.keys())-valsWithDefaults if len(unknownValues)>0: self.warning("Values for which no default was specified: "+ ", ".join(unknownValues)) if self.opts.verbose and len(vals)>0: print_("\nUsed values\n") nameLen=max(len("Name"), max([len(k) for k in vals.keys()])) format="%%%ds - %%s" % nameLen print_(format % ("Name","Value")) print_("-"*40) for k,v in sorted(iteritems(vals)): print_(format % (k,v)) print_("") else: self.info("\nNo values specified\n") self.checkCorrectOptions(vals) derivedScript=path.join(cName,self.opts.derivedParametersScript) derivedAdded=None derivedChanged=None if path.exists(derivedScript): self.info("Deriving variables in script",derivedScript) scriptText=open(derivedScript).read() def printError(*args): raise(Exception("Problem in "+derivedScript+"\n"+ " ".join(str(a) for a in args))) glob={'error':printError} oldVals=vals.copy() try: exec_(scriptText,glob,vals) except Exception as e: print_(e) self.error("Problem in",derivedScript) derivedAdded=[] derivedChanged=[] for k,v in iteritems(vals): if k not in oldVals: derivedAdded.append(k) elif vals[k]!=oldVals[k]: derivedChanged.append(k) if len(derivedChanged)>0 and (not self.opts.allowDerivedChanges and not configuration().getboolean("PrepareCase","AllowDerivedChanges")): self.error(self.opts.derivedParametersScript, "changed values of"," ".join(derivedChanged), "\nTo allow this set --allow-derived-changes or the configuration item 'AllowDerivedChanges'") if len(derivedAdded)>0: self.info("Added values:"," ".join(derivedAdded)) if len(derivedChanged)>0: self.info("Changed values:"," ".join(derivedChanged)) if len(derivedAdded)==0 and len(derivedChanged)==0: self.info("Nothing added or changed") if len(derivedAdded+derivedChanged)>0: derived=derivedAdded+derivedChanged if self.opts.verbose and len(vals)>0: print("\nDerived Values\n") nameLen=max(len("Name"), max([len(k) for k in derived])) format="%%%ds - %%s" % nameLen print_(format % ("Name","Value")) print_("-"*40) for k in sorted(derived): print_(format % (k,vals[k])) print_("") else: self.info("No script",derivedScript,"for derived values") if self.opts.onlyVariables: return self.__writeToStateFile(sol,"Starting") if self.opts.buildExample: allrun=open(path.join(cName,"Allrun"),"w") allrun.write("""#!/bin/sh cd ${0%/*} || exit 1 # Run from this directory . $WM_PROJECT_DIR/bin/tools/RunFunctions # Tutorial run functions """) else: allrun=None if self.opts.doClear: self.info("Clearing",cName) self.__writeToStateFile(sol,"Clearing") if self.opts.buildExample: allclean=open(path.join(cName,"Allclean"),"w") allclean.write("""#!/bin/sh cd ${0%/*} || exit 1 # Run from this directory . $WM_PROJECT_DIR/bin/tools/RunFunctions # Tutorial run functions . $WM_PROJECT_DIR/bin/tools/CleanFunctions # Tutorial clean functions """) else: allclean=None sol.clear(processor=True, pyfoam=True, vtk=True, verbose=True, removeAnalyzed=True, keepParallel=False, clearHistory=False, clearParameters=True, additional=["postProcessing"]) if allclean: allclean.write("\ncleanCase0\n") if self.opts.clearCaseScript: scriptName=path.join(sol.name,self.opts.clearCaseScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultClearCase)): scriptName=path.join(sol.name,self.defaultClearCase) else: scriptName=None for scr in self.opts.additionalClearCase: s=path.join(sol.name,scr) if path.exists(s): scriptName=s break if scriptName: self.info("Executing",scriptName,"for case clearing") if self.opts.verbose: echo="Clearing: " else: echo=None if allclean and path.basename(scriptName)!="Allclean": self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allclean) if allclean: allclean.write("\n#------------------------------------------------------------------------------\n") allclean.close() self.__writeToStateFile(sol,"Done clearing") if self.opts.writeParameters: fName=path.join(cName,self.parameterOutFile) self.info("Writing parameters to",fName) with WriteParameterFile(fName,noHeader=True) as w: w.content.update(vals,toString=True) w["foamVersion"]=vals["foamVersion"] w.writeFile() if self.opts.writeReport: fName=path.join(cName,self.parameterOutFile+".rst") self.info("Writing report to",fName) with open(fName,"w") as w: helper=RestructuredTextHelper(defaultHeading=1) w.write(".. title:: "+self.__strip(vals["caseName"])+"\n") w.write(".. sectnum::\n") w.write(".. header:: "+self.__strip(vals["caseName"])+"\n") w.write(".. header:: "+time.asctime()+"\n") w.write(".. footer:: ###Page### / ###Total###\n\n") w.write("Parameters set in case directory "+ helper.literal(self.__strip(vals["casePath"]))+" at "+ helper.emphasis(time.asctime())+"\n\n") w.write(".. contents::\n\n") if len(self.opts.valuesDicts): w.write(helper.heading("Parameter files")) w.write("Parameters read from files\n\n") w.write(helper.enumerateList([helper.literal(f) for f in self.opts.valuesDicts])) w.write("\n") if len(setValues)>0: w.write(helper.heading("Overwritten parameters")) w.write("These parameters were set from the command line\n\n") w.write(helper.definitionList(setValues)) w.write("\n") w.write(helper.heading("Parameters with defaults")) w.write(self.makeReport(vals)) if len(unknownValues)>0: w.write(helper.heading("Unspecified parameters")) w.write("If these parameters are actually used then specify them in "+ helper.literal(self.defaultParameterFile)+"\n\n") tab=helper.table(True) for u in unknownValues: tab.addRow(u) tab.addItem("Value",vals[u]) w.write(str(tab)) if not derivedAdded is None: w.write(helper.heading("Derived Variables")) w.write("Script with derived Parameters"+ helper.literal(derivedScript)+"\n\n") if len(derivedAdded)>0: w.write("These values were added:\n") tab=helper.table(True) for a in derivedAdded: tab.addRow(a) tab.addItem("Value",str(vals[a])) w.write(str(tab)) if len(derivedChanged)>0: w.write("These values were changed:\n") tab=helper.table(True) for a in derivedChanged: tab.addRow(a) tab.addItem("Value",str(vals[a])) tab.addItem("Old",str(oldVals[a])) w.write(str(tab)) w.write("The code of the script:\n") w.write(helper.code(scriptText)) self.addToCaseLog(cName) for over in self.opts.overloadDirs: self.info("Overloading files from",over) self.__writeToStateFile(sol,"Overloading") self.overloadDir(sol.name,over) self.__writeToStateFile(sol,"Initial") zeroOrig=None for ext in [self.opts.originalExt]+self.opts.zeroTimeOriginalExtensions: zo=path.join(sol.name,"0"+ext) if path.exists(zo): zeroOrig=zo break if zeroOrig is None: zeroOrig=path.join(sol.name,"0.org") zeroOrigShort=path.basename(zeroOrig) hasOrig=path.exists(zeroOrig) cleanZero=True if not hasOrig or self.opts.keepZero: self.info("Not going to clean '0'") if "0" in self.opts.cleanDirectories: self.opts.cleanDirectories.remove("0") cleanZero=False elif allrun: allrun.write("\nrm -rf 0\n") if self.opts.doCopy: if hasOrig and not self.opts.keepZero: self.info("Found",zeroOrigShort,". Clearing 0") zeroDir=path.join(sol.name,"0") if path.exists(zeroDir): rmtree(zeroDir) else: self.info("No 0-directory") self.info("") else: cleanZero=False if self.opts.doTemplates: self.__writeToStateFile(sol,"Templates") self.searchAndReplaceTemplates(sol.name, vals, self.opts.templateExt, ignoreDirectories=self.opts.ignoreDirectories) self.info("") backupZeroDir=None if self.opts.stopAfterTemplates: self.info("Stopping because of user request") self.__writeToStateFile(sol,"Finished OK") return if self.opts.doMeshCreate: self.__writeToStateFile(sol,"Meshing") if self.opts.meshCreateScript: scriptName=path.join(sol.name,self.opts.meshCreateScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultMeshCreate)): scriptName=path.join(sol.name,self.defaultMeshCreate) else: scriptName=None for scr in self.opts.additionalMeshCreate: s=path.join(sol.name,scr) if path.exists(s): scriptName=s break if scriptName: self.info("Executing",scriptName,"for mesh creation") if self.opts.verbose: echo="Mesh: " else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) else: self.info("No script for mesh creation found. Looking for 'blockMeshDict'") if sol.blockMesh()!="": self.info(sol.blockMesh(),"found. Executing 'blockMesh'") if allrun: allrun.write("\nrunApplication blockMesh\n") else: bm=BasicRunner(argv=["blockMesh","-case",sol.name]) bm.start() if not bm.runOK(): self.error("Problem with blockMesh") for r in sol.regions(): self.info("Checking region",r) s=SolutionDirectory(sol.name,region=r, archive=None,paraviewLink=self.opts.paraviewFile) if s.blockMesh()!="": self.info(s.blockMesh(),"found. Executing 'blockMesh'") if allrun: allrun.write("\nrunApplication blockMesh -region "+r+"\n") else: bm=BasicRunner(argv=["blockMesh","-case",sol.name, "-region",r]) bm.start() if not bm.runOK(): self.error("Problem with blockMesh") self.info("") if cleanZero and path.exists(zeroDir): self.warning("Mesh creation recreated 0-directory") if self.opts.keepZeroDirectoryFromMesh: backupZeroDir=zeroDir+".bakByPyFoam" self.info("Backing up",zeroDir,"to",backupZeroDir) move(zeroDir,backupZeroDir) else: self.info("Data in",zeroDir,"will be removed") self.__writeToStateFile(sol,"Done Meshing") if self.opts.doMeshCreate or self.opts.doMeshDecompose: self.__writeToStateFile(sol,"Decompose Mesh") if self.opts.decomposeMeshScript: scriptName=path.join(sol.name,self.opts.decomposeMeshScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultDecomposeMesh)): scriptName=path.join(sol.name,self.defaultDecomposeMesh) else: scriptName=None if vals["numberOfProcessors"]>1 and scriptName: self.info("Executing",scriptName,"for mesh decomposition") if self.opts.verbose: echo="Decompose Mesh: " else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) didDecompose=True else: if vals["numberOfProcessors"]>1: self.info("No script for mesh decomposition found") else: self.info("No mesh decomposition necessary") if self.opts.doCopy: self.__writeToStateFile(sol,"Copying") self.copyOriginals(sol.name) if path.splitext(zeroOrig)[1]!=self.opts.originalExt: self.copyOriginals(sol.name, extension=path.splitext(zeroOrig)[1], recursive=False) self.info("") if backupZeroDir: self.info("Copying backups from",backupZeroDir,"to",zeroDir) self.overloadDir(zeroDir,backupZeroDir) self.info("Removing backup",backupZeroDir) rmtree(backupZeroDir) if hasOrig and allrun: allrun.write("\ncp -r "+path.basename(zeroOrig)+" "+ path.basename(path.splitext(zeroOrig)[0])+"\n") if self.opts.doPostCopy: self.__writeToStateFile(sol,"After copying of 0.org") if self.opts.postCopyScript: scriptName=path.join(sol.name,self.opts.postCopyScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultPostCopy)): scriptName=path.join(sol.name,self.defaultPostCopy) else: scriptName=None if scriptName: self.info("Executing",scriptName,"after copying of 0.org") if self.opts.verbose: echo="PostCopy: " else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) if self.opts.doCopy or self.opts.doFieldDecompose: self.__writeToStateFile(sol,"Decompose Fields") if self.opts.decomposeFieldsScript: scriptName=path.join(sol.name,self.opts.decomposeFieldsScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultDecomposeFields)): scriptName=path.join(sol.name,self.defaultDecomposeFields) else: scriptName=None if vals["numberOfProcessors"]>1 and scriptName: self.info("Executing",scriptName,"for fields decomposition") if self.opts.verbose: echo="Decompose Fields: " else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) didDecompose=True else: if vals["numberOfProcessors"]>1: self.info("No script for fields decomposition found") else: self.info("No field decomposition necessary") if self.opts.doPostTemplates: self.__writeToStateFile(sol,"Post-templates") self.searchAndReplaceTemplates(sol.name, vals, self.opts.postTemplateExt, ignoreDirectories=self.opts.ignoreDirectories) self.info("") if self.opts.doCaseSetup: self.__writeToStateFile(sol,"Case setup") if self.opts.caseSetupScript: scriptName=path.join(sol.name,self.opts.caseSetupScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultCaseSetup)): scriptName=path.join(sol.name,self.defaultCaseSetup) else: scriptName=None if scriptName: self.info("Executing",scriptName,"for case setup") if self.opts.verbose: echo="Case:" else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) elif path.exists(path.join(sol.name,"system","setFieldsDict")): self.info("So setup script found. But 'setFieldsDict'. Executing setFields") if allrun: allrun.write("\nrunApplication setFields\n") else: sf=BasicRunner(argv=["setFields","-case",sol.name]) sf.start() if not sf.runOK(): self.error("Problem with setFields") else: self.info("No script for case-setup found. Nothing done") self.info("") self.__writeToStateFile(sol,"Done case setup") if self.opts.doCaseSetup or self.opts.doCaseDecompose: self.__writeToStateFile(sol,"Decompose Case") if self.opts.decomposeCaseScript: scriptName=path.join(sol.name,self.opts.decomposeCaseScript) if not path.exists(scriptName): self.error("Script",scriptName,"does not exist") elif path.exists(path.join(sol.name,self.defaultDecomposeCase)): scriptName=path.join(sol.name,self.defaultDecomposeCase) else: scriptName=None if vals["numberOfProcessors"]>1 and scriptName: self.info("Executing",scriptName,"for case decomposition") if self.opts.verbose: echo="Decompose Case: " else: echo=None self.executeScript(scriptName, workdir=sol.name, echo=echo, allrun=allrun) didDecompose=True else: if vals["numberOfProcessors"]>1: self.info("No script for case decomposition found") else: self.info("No case decomposition necessary") if self.opts.doFinalTemplates: self.__writeToStateFile(sol,"Final templates") self.searchAndReplaceTemplates(sol.name, vals, self.opts.finalTemplateExt, ignoreDirectories=self.opts.ignoreDirectories) if self.opts.doTemplateClean: self.info("Clearing templates") if self.opts.buildExample: self.opts.cleanDirectories.append(path.curdir) for d in self.opts.cleanDirectories: for e in [self.opts.templateExt, self.opts.postTemplateExt, self.opts.finalTemplateExt]: self.cleanExtension(path.join(sol.name,d),e) self.info("") sol.reread(force=True) nProcs = sol.nrProcs() if vals["numberOfProcessors"]>1 and not didDecompose: if nProcs!=vals["numberOfProcessors"]: f=self.error else: f=self.warning f("Case should be decomposed to",vals["numberOfProcessors"], "cpus but no decompose script (",self.defaultDecomposeMesh, self.defaultDecomposeFields,self.defaultDecomposeCase,") found") if vals["numberOfProcessors"]>1: if nProcs!=vals["numberOfProcessors"] and not self.opts.buildExample: self.error("Requested",vals["numberOfProcessors"],"but",nProcs, "processor directories present") elif nProcs>1: self.error(nProcs,"processor directories present although no decomposition was requested") self.info("Case setup finished") if allrun: if vals["numberOfProcessors"]>1: allrun.write("runParallel $(getApplication)\n") else: allrun.write("runApplication $(getApplication)\n") allrun.write("\n#------------------------------------------------------------------------------") allrun.close() if self.opts.buildExample: self.info("\nFinal preparations to make this an example case\n") import stat,os for a in ["Allrun","Allclean"]: f=path.join(cName,a) self.info("Making",f,"executable") st = os.stat(f) os.chmod(f, st.st_mode | stat.S_IEXEC) from glob import glob as gglob for p in ["PyFoamState.TheState","*.foam","*.parameters",self.opts.derivedParametersScript]: for f in gglob(path.join(cName,p)): self.info("Removing",f) remove(f) self.__writeToStateFile(sol,"Finished OK")