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

Source Code for Module PyFoam.Execution.BasicRunner

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