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

Source Code for Module PyFoam.Execution.BasicRunner

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