Package PyFoam :: Package Execution :: Module BasicRunner
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Execution.BasicRunner

  1  #  ICE Revision: $Id: BasicRunner.py 9166 2008-08-04 12:21:49Z bgschaid $  
  2  """Run a OpenFOAM command""" 
  3   
  4  import sys 
  5  import string 
  6  from os import path 
  7  from threading import Timer 
  8   
  9  from PyFoam.FoamInformation import oldAppConvention as oldApp 
 10   
 11  if not 'curdir' in dir(path) or not 'sep' in dir(path): 
 12      print "Warning: Inserting symbols into os.path (Python-Version<2.3)" 
 13      path.curdir='.' 
 14      path.sep   ='/' 
 15       
 16  from FoamThread import FoamThread 
 17  from PyFoam.Infrastructure.FoamServer import FoamServer 
 18  from PyFoam.Infrastructure.Logging import foamLogger 
 19  from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory 
 20  from PyFoam.RunDictionary.ParameterFile import ParameterFile 
 21  from PyFoam.Error import warning,error 
 22  from PyFoam import configuration as config 
 23   
24 -def restoreControlDict(ctrl):
25 """Timed function to avoid time-stamp-problems""" 26 warning("Restoring the controlDict") 27 ctrl.restore()
28
29 -class BasicRunner(object):
30 """Base class for the running of commands 31 32 When the command is run the output is copied to a LogFile and 33 (optionally) standard-out 34 35 The argument list assumes for the first three elements the 36 OpenFOAM-convention: 37 38 <cmd> <dir> <case> 39 40 The directory name for outputs is therefor created from <dir> and 41 <case> 42 43 Provides some handle-methods that are to be overloaded for 44 additional functionality""" 45
46 - def __init__(self,argv=None,silent=False,logname=None,lam=None,server=False,restart=False):
47 """@param argv: list with the tokens that are the command line 48 if not set the standard command line is used 49 @param silent: if True no output is sent to stdout 50 @param logname: name of the logfile 51 @param lam: Information about a parallel run 52 @param server: Whether or not to start the network-server 53 @type lam: PyFoam.Execution.ParallelExecution.LAMMachine""" 54 55 if sys.version_info < (2,3): 56 # Python 2.2 does not have the capabilities for the Server-Thread 57 if server: 58 warning("Can not start server-process because Python-Version is too old") 59 server=False 60 61 if argv==None: 62 self.argv=sys.argv[1:] 63 else: 64 self.argv=argv 65 66 if oldApp(): 67 self.dir=path.join(self.argv[1],self.argv[2]) 68 if self.argv[2][-1]==path.sep: 69 self.argv[2]=self.argv[2][:-1] 70 else: 71 self.dir=path.curdir 72 if "-case" in self.argv: 73 self.dir=self.argv[self.argv.index("-case")+1] 74 75 if logname==None: 76 logname="PyFoam."+path.basename(argv[0]) 77 78 try: 79 sol=self.getSolutionDirectory() 80 except OSError,e: 81 error("Solution directory",self.dir,"does not exist. No use running. Problem:",e) 82 83 self.silent=silent 84 self.lam=lam 85 self.origArgv=self.argv 86 87 if self.lam!=None: 88 self.argv=lam.buildMPIrun(self.argv) 89 self.cmd=string.join(self.argv," ") 90 foamLogger().info("Starting: "+self.cmd+" in "+path.abspath(path.curdir)) 91 self.logFile=path.join(self.dir,logname+".logfile") 92 93 self.fatalError=False 94 self.fatalFPE=False 95 self.fatalStackdump=False 96 97 self.warnings=0 98 self.started=False 99 100 self.isRestarted=False 101 if restart: 102 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 103 self.controlDict.replaceParameter("startFrom","latestTime") 104 self.isRestarted=True 105 else: 106 self.controlDict=None 107 108 self.run=FoamThread(self.cmd,self) 109 110 self.server=None 111 if server: 112 self.server=FoamServer(run=self.run,master=self) 113 self.server.setDaemon(True) 114 self.server.start() 115 try: 116 IP,PID,Port=self.server.info() 117 f=open(path.join(self.dir,"PyFoamServer.info"),"w") 118 print >>f,IP,PID,Port 119 f.close() 120 except AttributeError: 121 warning("There seems to be a problem with starting the server:",self.server,"with attributes",dir(self.server)) 122 self.server=None 123 124 self.createTime=None 125 self.nowTime=None 126 127 self.stopMe=False 128 self.writeRequested=False 129 130 self.endTriggers=[]
131
132 - def start(self):
133 """starts the command and stays with it till the end""" 134 135 self.started=True 136 fh=open(self.logFile,"w") 137 138 self.startHandle() 139 140 check=BasicRunnerCheck() 141 142 self.run.start() 143 144 while self.run.check(): 145 try: 146 self.run.read() 147 if not self.run.check(): 148 break 149 150 line=self.run.getLine() 151 152 tmp=check.getTime(line) 153 if check.controlDictRead(line): 154 if self.writeRequested: 155 warning("Preparing to reset controlDict to old glory") 156 Timer(config().getfloat("Execution","controlDictRestoreWait",default=30.), 157 restoreControlDict, 158 args=[self.controlDict]).start() 159 self.writeRequested=False 160 161 if tmp!=None: 162 self.nowTime=tmp 163 if self.createTime==None: 164 # necessary because interFoam reports no creation time 165 self.createTime=tmp 166 167 tmp=check.getCreateTime(line) 168 if tmp!=None: 169 self.createTime=tmp 170 171 if not self.silent: 172 print line 173 174 if line.find("FOAM FATAL ERROR")>=0 or line.find("FOAM FATAL IO ERROR")>=0: 175 self.fatalError=True 176 if line.find("Foam::sigFpe::sigFpeHandler")>=0: 177 self.fatalFPE=True 178 if line.find("Foam::error::printStack")>=0: 179 self.fatalStackdump=True 180 181 if self.fatalError and line!="": 182 foamLogger().error(line) 183 184 if line.find("FOAM Warning")>=0: 185 self.warnings+=1 186 187 if self.server!=None: 188 self.server._insertLine(line) 189 190 self.lineHandle(line) 191 192 fh.write(line+"\n") 193 fh.flush() 194 except KeyboardInterrupt,e: 195 foamLogger().warning("Keyboard Interrupt") 196 self.run.interrupt() 197 198 self.stopHandle() 199 200 for t in self.endTriggers: 201 t() 202 203 fh.close() 204 205 if self.server!=None: 206 self.server.deregister() 207 self.server.kill() 208 209 foamLogger().info("Finished")
210
211 - def runOK(self):
212 """checks whether the run was successful""" 213 if self.started: 214 return not self.fatalError and not self.fatalFPE and not self.fatalStackdump 215 else: 216 return False
217
218 - def startHandle(self):
219 """to be called before the program is started""" 220 pass
221
222 - def stopGracefully(self):
223 """Tells the runner to stop at the next convenient time""" 224 if not self.stopMe: 225 self.stopMe=True 226 if not self.isRestarted: 227 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 228 self.controlDict.replaceParameter("stopAt","writeNow") 229 warning("Stopping run at next write")
230
231 - def writeResults(self):
232 """Writes the next possible time-step""" 233 # warning("writeResult is not yet implemented") 234 if not self.writeRequested: 235 if not self.isRestarted: 236 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 237 self.controlDict.replaceParameter("writeControl","timeStep") 238 self.controlDict.replaceParameter("writeInterval","1") 239 self.writeRequested=True
240
241 - def stopHandle(self):
242 """called after the program has stopped""" 243 if self.stopMe or self.isRestarted: 244 self.controlDict.restore()
245
246 - def lineHandle(self,line):
247 """called every time a new line is read""" 248 pass
249
250 - def logName(self):
251 """Get the name of the logfiles""" 252 return self.logFile
253
254 - def getSolutionDirectory(self,archive=None):
255 """@return: The directory of the case 256 @rtype: PyFoam.RunDictionary.SolutionDirectory 257 @param archive: Name of the directory for archiving results""" 258 259 return SolutionDirectory(self.dir,archive=archive)
260
261 - def addEndTrigger(self,f):
262 """@param f: A function that is to be executed at the end of the simulation""" 263 self.endTriggers.append(f)
264 265 import re 266
267 -class BasicRunnerCheck(object):
268 """A small class that does primitve checking for BasicRunner 269 Duplicates other efforts, but ....""" 270 271 floatRegExp="[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?" 272
273 - def __init__(self):
274 self.timeExpr=re.compile("^Time = (%f%)$".replace("%f%",self.floatRegExp)) 275 self.createExpr=re.compile("^Create mesh for time = (%f%)$".replace("%f%",self.floatRegExp))
276
277 - def getTime(self,line):
278 """Does this line contain time information?""" 279 m=self.timeExpr.match(line) 280 if m: 281 return float(m.group(1)) 282 else: 283 return None
284
285 - def getCreateTime(self,line):
286 """Does this line contain mesh time information?""" 287 m=self.createExpr.match(line) 288 if m: 289 return float(m.group(1)) 290 else: 291 return None
292
293 - def controlDictRead(self,line):
294 """Was the controlDict reread?""" 295 if line.find("Reading object controlDict from file"): 296 return True 297 else: 298 return False
299