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 7361 2011-03-17T09:41:49.879693Z 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,asctime 
 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,debug 
 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 writeState=True):
61 """@param argv: list with the tokens that are the command line 62 if not set the standard command line is used 63 @param silent: if True no output is sent to stdout 64 @param logname: name of the logfile 65 @param compressLog: Compress the logfile into a gzip 66 @param lam: Information about a parallel run 67 @param server: Whether or not to start the network-server 68 @type lam: PyFoam.Execution.ParallelExecution.LAMMachine 69 @param noLog: Don't output a log file 70 @param remark: User defined remark about the job 71 @param jobId: Job ID of the controlling system (Queueing system) 72 @param writeState: Write the state to some files in the case""" 73 74 if sys.version_info < (2,3): 75 # Python 2.2 does not have the capabilities for the Server-Thread 76 if server: 77 warning("Can not start server-process because Python-Version is too old") 78 server=False 79 80 if argv==None: 81 self.argv=sys.argv[1:] 82 else: 83 self.argv=argv 84 85 if oldApp(): 86 self.dir=path.join(self.argv[1],self.argv[2]) 87 if self.argv[2][-1]==path.sep: 88 self.argv[2]=self.argv[2][:-1] 89 else: 90 self.dir=path.curdir 91 if "-case" in self.argv: 92 self.dir=self.argv[self.argv.index("-case")+1] 93 94 if logname==None: 95 logname="PyFoam."+path.basename(argv[0]) 96 97 try: 98 sol=self.getSolutionDirectory() 99 except OSError,e: 100 error("Solution directory",self.dir,"does not exist. No use running. Problem:",e) 101 102 self.silent=silent 103 self.lam=lam 104 self.origArgv=self.argv 105 self.writeState=writeState 106 self.__lastLastSeenWrite=0 107 self.__lastNowTimeWrite=0 108 109 if self.lam!=None: 110 self.argv=lam.buildMPIrun(self.argv) 111 if config().getdebug("ParallelExecution"): 112 debug("Command line:",string.join(self.argv)) 113 self.cmd=string.join(self.argv," ") 114 foamLogger().info("Starting: "+self.cmd+" in "+path.abspath(path.curdir)) 115 self.logFile=path.join(self.dir,logname+".logfile") 116 self.noLog=noLog 117 self.compressLog=compressLog 118 if self.compressLog: 119 self.logFile+=".gz" 120 121 self.fatalError=False 122 self.fatalFPE=False 123 self.fatalStackdump=False 124 125 self.warnings=0 126 self.started=False 127 128 self.isRestarted=False 129 if restart: 130 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 131 self.controlDict.replaceParameter("startFrom","latestTime") 132 self.isRestarted=True 133 else: 134 self.controlDict=None 135 136 self.run=FoamThread(self.cmd,self) 137 138 self.server=None 139 if server: 140 self.server=FoamServer(run=self.run,master=self) 141 self.server.setDaemon(True) 142 self.server.start() 143 try: 144 IP,PID,Port=self.server.info() 145 f=open(path.join(self.dir,"PyFoamServer.info"),"w") 146 print >>f,IP,PID,Port 147 f.close() 148 except AttributeError: 149 warning("There seems to be a problem with starting the server:",self.server,"with attributes",dir(self.server)) 150 self.server=None 151 152 self.createTime=None 153 self.nowTime=None 154 self.startTimestamp=time() 155 156 self.stopMe=False 157 self.writeRequested=False 158 159 self.endTriggers=[] 160 161 self.lastLogLineSeen=None 162 self.lastTimeStepSeen=None 163 164 self.remark=remark 165 self.jobId=jobId
166
167 - def start(self):
168 """starts the command and stays with it till the end""" 169 170 self.started=True 171 if not self.noLog: 172 if self.compressLog: 173 fh=gzip.open(self.logFile,"w") 174 else: 175 fh=open(self.logFile,"w") 176 177 self.startHandle() 178 179 self.writeStartTime() 180 self.writeTheState("Running") 181 182 check=BasicRunnerCheck() 183 184 self.run.start() 185 interrupted=False 186 187 while self.run.check(): 188 try: 189 self.run.read() 190 if not self.run.check(): 191 break 192 193 line=self.run.getLine() 194 self.lastLogLineSeen=time() 195 self.writeLastSeen() 196 197 tmp=check.getTime(line) 198 if check.controlDictRead(line): 199 if self.writeRequested: 200 warning("Preparing to reset controlDict to old glory") 201 Timer(config().getfloat("Execution","controlDictRestoreWait",default=30.), 202 restoreControlDict, 203 args=[self.controlDict,self]).start() 204 self.writeRequested=False 205 206 if tmp!=None: 207 self.nowTime=tmp 208 self.writeTheState("Running",always=False) 209 self.writeNowTime() 210 self.lastTimeStepSeen=time() 211 if self.createTime==None: 212 # necessary because interFoam reports no creation time 213 self.createTime=tmp 214 215 tmp=check.getCreateTime(line) 216 if tmp!=None: 217 self.createTime=tmp 218 219 if not self.silent: 220 try: 221 print line 222 except IOError,e: 223 if e.errno!=32: 224 raise e 225 else: 226 # Pipe was broken 227 self.run.interrupt() 228 229 if line.find("FOAM FATAL ERROR")>=0 or line.find("FOAM FATAL IO ERROR")>=0: 230 self.fatalError=True 231 if line.find("Foam::sigFpe::sigFpeHandler")>=0: 232 self.fatalFPE=True 233 if line.find("Foam::error::printStack")>=0: 234 self.fatalStackdump=True 235 236 if self.fatalError and line!="": 237 foamLogger().error(line) 238 239 if line.find("FOAM Warning")>=0: 240 self.warnings+=1 241 242 if self.server!=None: 243 self.server._insertLine(line) 244 245 self.lineHandle(line) 246 247 if not self.noLog: 248 fh.write(line+"\n") 249 fh.flush() 250 251 except KeyboardInterrupt,e: 252 foamLogger().warning("Keyboard Interrupt") 253 self.run.interrupt() 254 self.writeTheState("Interrupted") 255 interrupted=True 256 257 self.writeNowTime(force=True) 258 259 self.stopHandle() 260 261 if not interrupted: 262 self.writeTheState("Finished") 263 264 for t in self.endTriggers: 265 t() 266 267 if not self.noLog: 268 fh.close() 269 270 if self.server!=None: 271 self.server.deregister() 272 self.server.kill() 273 274 foamLogger().info("Finished")
275
276 - def writeToStateFile(self,fName,message):
277 """Write a message to a state file""" 278 if self.writeState: 279 open(path.join(self.dir,"PyFoamState."+fName),"w").write(message+"\n")
280
281 - def writeStartTime(self):
282 """Write the real time the run was started at""" 283 self.writeToStateFile("StartedAt",asctime())
284
285 - def writeTheState(self,state,always=True):
286 """Write the current state the run is in""" 287 if always or (time()-self.__lastLastSeenWrite)>9: 288 self.writeToStateFile("TheState",state)
289
290 - def writeLastSeen(self):
291 if (time()-self.__lastLastSeenWrite)>10: 292 self.writeToStateFile("LastOutputSeen",asctime()) 293 self.__lastLastSeenWrite=time()
294
295 - def writeNowTime(self,force=False):
296 if (time()-self.__lastNowTimeWrite)>10 or force: 297 self.writeToStateFile("CurrentTime",str(self.nowTime)) 298 self.__lastNowTimeWrite=time()
299
300 - def runOK(self):
301 """checks whether the run was successful""" 302 if self.started: 303 return not self.fatalError and not self.fatalFPE and not self.fatalStackdump # and self.run.getReturnCode()==0 304 else: 305 return False
306
307 - def startHandle(self):
308 """to be called before the program is started""" 309 pass
310
311 - def stopGracefully(self):
312 """Tells the runner to stop at the next convenient time""" 313 if not self.stopMe: 314 self.stopMe=True 315 if not self.isRestarted: 316 if self.controlDict: 317 warning("The controlDict has already been modified. Restoring will be problementic") 318 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 319 self.controlDict.replaceParameter("stopAt","writeNow") 320 warning("Stopping run at next write")
321
322 - def writeResults(self):
323 """Writes the next possible time-step""" 324 # warning("writeResult is not yet implemented") 325 if not self.writeRequested: 326 if not self.isRestarted: 327 if self.controlDict: 328 warning("The controlDict has already been modified. Restoring will be problementic") 329 self.controlDict=ParameterFile(path.join(self.dir,"system","controlDict"),backup=True) 330 self.controlDict.replaceParameter("writeControl","timeStep") 331 self.controlDict.replaceParameter("writeInterval","1") 332 self.writeRequested=True
333
334 - def stopHandle(self):
335 """called after the program has stopped""" 336 if self.stopMe or self.isRestarted: 337 self.controlDict.restore()
338
339 - def lineHandle(self,line):
340 """called every time a new line is read""" 341 pass
342
343 - def logName(self):
344 """Get the name of the logfiles""" 345 return self.logFile
346
347 - def getSolutionDirectory(self,archive=None):
348 """@return: The directory of the case 349 @rtype: PyFoam.RunDictionary.SolutionDirectory 350 @param archive: Name of the directory for archiving results""" 351 352 return SolutionDirectory(self.dir,archive=archive,parallel=True)
353
354 - def addEndTrigger(self,f):
355 """@param f: A function that is to be executed at the end of the simulation""" 356 self.endTriggers.append(f)
357 358 import re 359
360 -class BasicRunnerCheck(object):
361 """A small class that does primitve checking for BasicRunner 362 Duplicates other efforts, but ....""" 363 364 floatRegExp="[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?" 365
366 - def __init__(self):
367 self.timeExpr=re.compile("^Time = (%f%)$".replace("%f%",self.floatRegExp)) 368 self.createExpr=re.compile("^Create mesh for time = (%f%)$".replace("%f%",self.floatRegExp))
369
370 - def getTime(self,line):
371 """Does this line contain time information?""" 372 m=self.timeExpr.match(line) 373 if m: 374 return float(m.group(1)) 375 else: 376 return None
377
378 - def getCreateTime(self,line):
379 """Does this line contain mesh time information?""" 380 m=self.createExpr.match(line) 381 if m: 382 return float(m.group(1)) 383 else: 384 return None
385
386 - def controlDictRead(self,line):
387 """Was the controlDict reread?""" 388 if line.find("Reading object controlDict from file")>=0: 389 return True 390 else: 391 return False
392