def purgeFile(self): """Undo all the manipulations done by PyFOAM Goes through the file and removes all lines that were added""" if not self.name: error("File-handle", str(self.fh), "can not be purged") rmExp = re.compile("^" + self.removedString + "(.*)$") addExp = re.compile("^(.*)" + self.addedString + "$") l = LineReader() self.openFile() (fh, fn) = self.makeTemp() while l.read(self.fh): toPrint = l.line m = addExp.match(l.line) if m != None: continue m = rmExp.match(l.line) if m != None: toPrint = m.group(1) self.writeEncoded(fh, toPrint + "\n") self.closeFile() fh.close() os.rename(fn, self.name)
def replaceParameter(self,parameter,newval): """writes the value of a parameter :param parameter: name of the parameter :param newval: the new value :return: old value of the parameter""" oldVal=self.readParameter(parameter) exp=self.parameterPattern(parameter) l=LineReader() self.openFile() (fh,fn)=self.makeTemp() while l.read(self.fh): toPrint=l.line m=exp.match(l.line) if m!=None: if m.group(1).find(self.removedString)<0: toPrint =self.removedString+l.line+"\n" toPrint+=parameter+" "+str(newval)+"; "+self.addedString fh.write(toPrint+"\n") self.closeFile() fh.close() os.rename(fn,self.name) return oldVal
def __init__(self, progress=False): """ :param progress: Print time progress on console? """ self.analyzers = {} self.time = "" self.oDir = "" self.line = LineReader(config().getboolean("SolverOutput", "stripSpaces")) self.timeListeners = [] self.timeTriggers = [] self.resetFileTriggers = [] self.customExpr = re.compile("Custom([0-9]+)_(.+)") if progress: self.progressOut = ProgressOutput(stdout) else: self.progressOut = ProgressOutput() # tm=CountLineAnalyzer() tm = TimeLineAnalyzer() self.addAnalyzer("Time", tm) tm.addListener(self.setTime) self.analyzedLines = 0
def purgeFile(self): """Undo all the manipulations done by PyFOAM Goes through the file and removes all lines that were added""" rmExp= re.compile("^"+self.removedString+"(.*)$") addExp=re.compile("^(.*)"+self.addedString+"$") l=LineReader() self.openFile() (fh,fn)=self.makeTemp() while l.read(self.fh): toPrint=l.line m=addExp.match(l.line) if m!=None: continue m=rmExp.match(l.line) if m!=None: toPrint=m.group(1) self.writeEncoded(fh,toPrint+"\n") self.closeFile() fh.close() os.rename(fn,self.name)
def __init__(self, filename, silent=False, tailLength=1000, sleep=0.1, follow=True): """:param filename: name of the logfile to watch :param silent: if True no output is sent to stdout :param tailLength: number of bytes at the end of the fail that should be output. :param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis :param sleep: interval to sleep if no line is returned""" self.filename = filename self.silent = silent self.tail = tailLength self.sleep = sleep self.follow = follow self.isTailing = False if not path.exists(self.filename): print_("Error: Logfile ", self.filename, "does not exist") self.reader = LineReader(config().getboolean("SolverOutput", "stripSpaces"))
def refineMesh(self,factors,offset=(0,0,0)): """Refine the Mesh by multiplying the number of cells in the blocks @param factors: either a scalar to scale in all directions or a tuple with the value for each direction @param offset: an optional tuple for an additionnal offset value for each direction""" if type(factors)!=tuple: f=(factors,factors,factors) else: f=factors startPattern=re.compile("^\s*blocks") endPattern=re.compile("^\s\);") hexPattern=re.compile("^(\s*hex\s*\(.+\)\s+\(\s*)(\d+)\s+(\d+)\s+(\d+)(\s*\).*)$") inBlock=False l=LineReader() self.openFile() (fh,fn)=self.makeTemp() while l.read(self.fh): toPrint=l.line if not inBlock: if startPattern.match(l.line): inBlock=True else: if endPattern.match(l.line): inBlock=False else: m=hexPattern.match(l.line) if m!=None: g=m.groups() toPrint =self.removedString+l.line+"\n" toPrint+="%s%d %d %d%s" % ( g[0], int(g[1])*f[0]+offset[0], int(g[2])*f[1]+offset[1], int(g[3])*f[2]+offset[2], g[4]) toPrint+=" "+self.addedString fh.write(toPrint+"\n") self.closeFile() fh.close() os.rename(fn,self.name)
def __init__(self, filenames, silent=False, tailLength=1000, sleep=0.1, endTime=None, follow=True): """:param filename: name of the logfile to watch :param silent: if True no output is sent to stdout :param tailLength: number of bytes at the end of the fail that should be output. :param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis :param sleep: interval to sleep if no line is returned""" if type(filenames) is list: meshTimes = [] createMesh = "Create mesh for time = " for fName in filenames: meshTime = None with open(fName) as f: for l in f.readlines()[:100]: if l.find(createMesh) == 0: meshTime = float(l[len(createMesh):]) break meshTimes.append((fName, meshTime)) meshTimes.sort(key=lambda x: 1e50 if x[1] is None else x[1]) filenames = [m[0] for m in meshTimes] self.filename = filenames[0] self.nextFiles = filenames[1:] self.changeTimes = [m[1] for m in meshTimes[1:]] else: self.filename = filenames self.nextFiles = [] self.changeTimes = [] self._changeFileHooks = [] self.silent = silent self.tail = tailLength self.sleep = sleep self.follow = follow self.endTime = endTime self.isTailing = False if not path.exists(self.filename): print_("Error: Logfile ", self.filename, "does not exist") self.reader = LineReader(config().getboolean("SolverOutput", "stripSpaces"))
def replaceBoundary(self,name,newval): """write the value at a boundary :param name: the name of the boundary patch :param newval: the new value""" exp=self.valuePattern() l=LineReader() self.openFile() fh,fn=self.makeTemp() self.goTo(l,"boundaryField",out=fh,echoLast=True) self.goTo(l,name,out=fh,echoLast=True) m=self.goMatch(l,exp,out=fh,stop=self.stopPattern()) if m!=None: if type(m)==str: self.writeEncoded(fh,"value uniform "+str(newval)+"; "+self.addedString+"\n") self.writeEncoded(fh,l.line+"\n") else: self.writeEncoded(fh,self.removedString+l.line+"\n") self.writeEncoded(fh,"value uniform "+str(newval)+"; "+self.addedString+"\n") else: self.writeEncoded(fh,l.line+"\n") self.copyRest(l,fh) self.closeFile() fh.close() os.rename(fn,self.realName())
def readInternalUniform(self): """read the value of the internal field""" exp=self.internalPatternUniform() erg="" l=LineReader() self.openFile() while l.read(self.fh): m=exp.match(l.line) if m!=None: erg=m.group(1) break self.closeFile() return erg
def readDimension(self): """read the dimension of the field""" exp=self.dimensionPattern() erg="" l=LineReader() self.openFile() while l.read(self.fh): m=exp.match(l.line) if m!=None: erg=m.group(1) break self.closeFile() return erg
def getSize(self): """:return: the size of the list""" size=-1 # should be long l=LineReader() self.openFile() while l.read(self.fh): try: size=long(l.line) break except ValueError: pass self.closeFile() return size
def getSize(self): """:return: the size of the list""" size = -1 # should be long l = LineReader() self.openFile() while l.read(self.fh): try: size = long(l.line) break except ValueError: pass self.closeFile() return size
def __init__(self, cmdline, runner): """:param cmdline:cmdline - Command line of the OpenFOAM command :param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline = cmdline self.runner = runner self.output = None self.reader = LineReader(config().getboolean("SolverOutput", "stripSpaces")) self.keyboardInterupted = False self.isLinux = False self.isDarwin = False self.isWindows = False self.threadPid = -1 self.who = RUSAGE_CHILDREN if uname()[0] == "Linux": self.isLinux = True self.linuxMaxMem = 0 elif uname()[0] == "Darwin": self.isDarwin = True elif uname()[0] == "Windows": self.isWindows = True self.resStart = None self.resEnd = None self.timeStart = None self.timeEnd = None self.timerTime = 5. self.stateLock = Lock() self.setState(False) self.status = None self.returncode = None self.lineLock = Lock() self.line = "" self.stateLock.acquire()
def readParameter(self,parameter): """reads the value of a parameter parameter - name of the parameter""" exp=self.parameterPattern(parameter) l=LineReader() self.openFile() erg="" while l.read(self.fh): m=exp.match(l.line) if m!=None: if m.group(1).find(self.removedString)<0: erg=m.group(2) break self.closeFile() return erg
def __init__(self, progress=False): """ @param progress: Print time progress on console? """ self.analyzers = {} self.time = "" self.oDir = "" self.line = LineReader() self.timeListeners = [] self.timeTriggers = [] self.customExpr = re.compile("Custom([0-9]+)_(.+)") self.progressOut = None if progress: self.progressOut = ProgressOutput(stdout) tm = TimeLineAnalyzer(progress=progress) self.addAnalyzer("Time", tm) tm.addListener(self.setTime)
def readParameter(self, parameter): """reads the value of a parameter parameter - name of the parameter""" exp = self.parameterPattern(parameter) l = LineReader() self.openFile() erg = "" while l.read(self.fh): m = exp.match(l.line) if m != None: if m.group(1).find(self.removedString) < 0: erg = m.group(2) break self.closeFile() return erg
def __init__(self,filenames, silent=False, tailLength=1000, sleep=0.1, follow=True): """:param filename: name of the logfile to watch :param silent: if True no output is sent to stdout :param tailLength: number of bytes at the end of the fail that should be output. :param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis :param sleep: interval to sleep if no line is returned""" if type(filenames) is list: meshTimes=[] createMesh="Create mesh for time = " for fName in filenames: meshTime=None with open(fName) as f: for l in f.readlines()[:100]: if l.find(createMesh)==0: meshTime=float(l[len(createMesh):]) break meshTimes.append((fName,meshTime)) meshTimes.sort(key=lambda x:1e50 if x[1] is None else x[1]) filenames=[m[0] for m in meshTimes] self.filename=filenames[0] self.nextFiles=filenames[1:] self.changeTimes=[m[1] for m in meshTimes[1:]] else: self.filename=filenames self.nextFiles=[] self.changeTimes=[] self._changeFileHooks=[] self.silent=silent self.tail=tailLength self.sleep=sleep self.follow=follow self.isTailing=False if not path.exists(self.filename): print_("Error: Logfile ",self.filename,"does not exist") self.reader=LineReader(config().getboolean("SolverOutput","stripSpaces"))
def __init__(self,progress=False): """ @param progress: Print time progress on console? """ self.analyzers={} self.time="" self.oDir="" self.line=LineReader() self.timeListeners=[] self.timeTriggers=[] self.progressOut=None if progress: self.progressOut=ProgressOutput(stdout) tm=TimeLineAnalyzer(progress=progress) self.addAnalyzer("Time",tm) tm.addListener(self.setTime)
def readBoundary(self,name): """read the value at a boundary name - the name of the boundary patch""" exp=self.valuePattern() erg="" l=LineReader() self.openFile() self.goTo(l,"boundaryField") self.goTo(l,name) m=self.goMatch(l,exp) if m!=None: erg=m.group(1) self.closeFile() return erg
def __init__(self,cmdline,runner): """:param cmdline:cmdline - Command line of the OpenFOAM command :param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline=cmdline self.runner=runner self.output=None self.reader=LineReader(config().getboolean("SolverOutput","stripSpaces")) self.keyboardInterupted=False self.isLinux=False self.isDarwin=False self.isWindows=False self.threadPid=-1 self.who=RUSAGE_CHILDREN if uname()[0]=="Linux": self.isLinux=True self.linuxMaxMem=0 elif uname()[0]=="Darwin": self.isDarwin=True elif uname()[0]=="Windows": self.isWindows=True self.resStart=None self.resEnd=None self.timeStart=None self.timeEnd=None self.timerTime=5. self.stateLock=Lock() self.setState(False) self.status=None self.returncode=None self.lineLock=Lock() self.line="" self.stateLock.acquire()
def __init__(self,progress=False): """ @param progress: Print time progress on console? """ self.analyzers={} self.time="" self.oDir="" self.line=LineReader(config().getboolean("SolverOutput","stripSpaces")) self.timeListeners=[] self.timeTriggers=[] self.customExpr=re.compile("Custom([0-9]+)_(.+)") self.progressOut=None if progress: self.progressOut=ProgressOutput(stdout) tm=TimeLineAnalyzer(progress=progress) self.addAnalyzer("Time",tm) tm.addListener(self.setTime)
def __init__(self,cmdline,runner): """@param cmdline:cmdline - Command line of the OpenFOAM command @param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline=cmdline self.runner=runner self.output=None self.reader=LineReader() self.isLinux=False self.isDarwin=False self.threadPid=-1 self.who=RUSAGE_CHILDREN if uname()[0]=="Linux": self.isLinux=True self.linuxMaxMem=0 elif uname()[0]=="Darwin": self.isDarwin=True self.resStart=None self.resEnd=None self.timeStart=None self.timeEnd=None self.timerTime=5. self.stateLock=Lock() self.setState(False) self.status=None self.returncode=None self.lineLock=Lock() self.line="" self.stateLock.acquire()
def __init__(self,filename, silent=False, tailLength=1000, sleep=0.1, follow=True): """@param filename: name of the logfile to watch @param silent: if True no output is sent to stdout @param tailLength: number of bytes at the end of the fail that should be output. @param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis @param sleep: interval to sleep if no line is returned""" self.filename=filename self.silent=silent self.tail=tailLength self.sleep=sleep self.follow=follow self.isTailing=False if not path.exists(self.filename): print_("Error: Logfile ",self.filename,"does not exist") self.reader=LineReader()
def replaceInternal(self,newval): """overwrite the value of the internal field newval - the new value""" exp=self.internalPatternGeneral() l=LineReader() self.openFile() fh,fn=self.makeTemp() m=self.goMatch(l,exp,out=fh) if m!=None: self.writeEncoded(fh,self.removedString+l.line+"\n") self.writeEncoded(fh,"internalField uniform "+str(newval)+"; "+self.addedString+"\n") else: self.writeEncoded(fh,l.line+"\n") self.copyRest(l,fh) self.closeFile() fh.close() os.rename(fn,self.realName())
class FoamThread(Thread): """Thread running an OpenFOAM command The output of the command can be accessed in a thread-safe manner, line by line Designed to be used by the BasicRunner-class""" def __init__(self,cmdline,runner): """@param cmdline:cmdline - Command line of the OpenFOAM command @param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline=cmdline self.runner=runner self.output=None self.reader=LineReader() self.isLinux=False self.isDarwin=False self.threadPid=-1 self.who=RUSAGE_CHILDREN if uname()[0]=="Linux": self.isLinux=True self.linuxMaxMem=0 elif uname()[0]=="Darwin": self.isDarwin=True self.resStart=None self.resEnd=None self.timeStart=None self.timeEnd=None self.timerTime=5. self.stateLock=Lock() self.setState(False) self.status=None self.returncode=None self.lineLock=Lock() self.line="" self.stateLock.acquire() def run(self): """start the command""" # print "Starting ",self.cmdline self.resStart=getrusage(self.who) self.timeStart=time() if sys.version_info<(2,4): run=Popen4(self.cmdline) self.output=run.fromchild else: run=subprocess.Popen(self.cmdline,shell=True,bufsize=0, stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.STDOUT,close_fds=True) self.output=run.stdout self.run=run self.threadPid=run.pid foamLogger().info("Started with PID %d" % self.threadPid) if self.isLinux: # print "Starting Timer" self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self]) self.timer.start() # print "Starting Timer" self.timer2=Timer(0.5*self.timerTime,checkForStopFile,args=[self]) self.timer2.start() self.hasSomethingToSay=True self.stateLock.release() try: # print "Waiting",time() self.status=run.wait() # Python 2.3 on Mac OS X never seems to reach this point # print "After wait",time() # print "Status:",self.status # to give a chance to read the remaining output if self.hasSomethingToSay: sleep(2.) while self.reader.read(self.output): print "Unused output:",self.reader.line except OSError,e: print "Exeption caught:",e self.stopTimer() self.threadPid=-1 self.resEnd=getrusage(self.who) self.timeEnd=time() # print "End:",self.timeEnd # print "Returned",self.status self.getReturnCode()
class BasicWatcher(object): """Base class for watching the output of commands Works like the UNIX-command 'tail -f <file>': the last lines of the file are output. If the file grows then these lines are output as they arrive""" def __init__(self,filename, silent=False, tailLength=1000, sleep=0.1, follow=True): """@param filename: name of the logfile to watch @param silent: if True no output is sent to stdout @param tailLength: number of bytes at the end of the fail that should be output. @param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis @param sleep: interval to sleep if no line is returned""" self.filename=filename self.silent=silent self.tail=tailLength self.sleep=sleep self.follow=follow self.isTailing=False if not path.exists(self.filename): print_("Error: Logfile ",self.filename,"does not exist") self.reader=LineReader() def getSize(self): """@return: the current size (in bytes) of the file""" return os.stat(self.filename)[stat.ST_SIZE] def start(self): """Reads the file and does the processing""" currSize=self.getSize() fn,ext=path.splitext(self.filename) if ext=='.gz': fh=gzip.open(self.filename) else: fh=open(self.filename) self.startHandle() while self.follow or currSize>self.reader.bytesRead(): try: status=self.reader.read(fh) if status: line=self.reader.line if (currSize-self.reader.bytesRead())<=self.tail: if not self.isTailing: self.isTailing=True self.timeHandle() self.tailingHandle() if not self.silent: print_(line) self.lineHandle(line) else: if self.reader.userSaidStop(): break sleep(self.sleep) except KeyboardInterrupt: print_("Watcher: Keyboard interrupt") break self.stopHandle() fh.close() def startHandle(self): """to be called before the program is started""" pass def stopHandle(self): """called after the program has stopped""" pass def tailingHandle(self): """called when the first line is output""" pass def lineHandle(self,line): """called every time a new line is read""" pass
class FoamLogAnalyzer(object): """Base class for all analyzers Administrates and calls a number of LogLineAnlayzers for each line""" def __init__(self, progress=False): """ :param progress: Print time progress on console? """ self.analyzers = {} self.time = "" self.oDir = "" self.line = LineReader(config().getboolean("SolverOutput", "stripSpaces")) self.timeListeners = [] self.timeTriggers = [] self.resetFileTriggers = [] self.customExpr = re.compile("Custom([0-9]+)_(.+)") if progress: self.progressOut = ProgressOutput(stdout) else: self.progressOut = ProgressOutput() # tm=CountLineAnalyzer() tm = TimeLineAnalyzer() self.addAnalyzer("Time", tm) tm.addListener(self.setTime) self.analyzedLines = 0 def tearDown(self): """Remove reference to self in children (hoping to remove circular dependencies)""" for a in list(self.analyzers.values()): a.tearDown() a.setParent(None) def collectData(self, structured=False): """Collect dictionaries of collected data (current state) from the analyzers :return: the dictionary""" result = {} for nm in self.analyzers: data = self.analyzers[nm].getCurrentData(structured=structured) if len(data) > 0: m = self.customExpr.match(nm) if m: if not "Custom" in result: result["Custom"] = {} nr, name = m.groups() result["Custom"][name] = data # this will store custom data twice. But we'll keep it # for backward-compatibility result[nm] = data return result def summarizeData(self, col=80): """Get a summary of the data""" result = "=" * col result += "\nt = {:20}\n".format(self.getTime()) data = self.collectData(structured=True) for k, v in iteritems(data): if k.find("Custom") == 0 and len(k) > 9 and k[8] == "_": kk = k[9:] elif k in ["Custom"]: continue else: kk = k if isinstance(v, (dict, )): result += kk + " " + "-" * (col - len(kk) - 1) + "\n" isDicts = True for k1, v1 in iteritems(v): if not isinstance(v1, (dict, )): isDicts = False break if not isDicts: maxLen = max([len(k1) for k1 in v.keys()]) wFormat = "{:%d} : {:8g}" % maxLen chunks = [ wFormat.format(k1, v[k1]) for k1 in sorted(v.keys()) ] maxLen = max([len(c) for c in chunks]) chunks = [ c if len(c) >= maxLen else c + " " * (maxLen - len(c)) for c in chunks ] nrChunks = col // (max([len(e) for e in chunks]) + 3) for i in range(0, len(chunks), nrChunks): result += " | ".join(chunks[i:(i + nrChunks)]) + "\n" else: maxLen = 0 for k1, v1 in iteritems(v): maxLen = max( maxLen, max([len(k1) + 2 - 8] + [len(k2) for k2 in v1.keys()])) wFormat = "{:%d} : {:8g}" % maxLen chunks = {} chunkLen = 0 for k1, v1 in iteritems(v): chunks[k1] = [ wFormat.format(k2, v1[k2]) for k2 in sorted(v1.keys()) ] chunkLen = max(chunkLen, max([len(e) for e in chunks[k1]])) for k1 in sorted(v.keys()): chunks[k1] = [ k1 + " " + "_" * (chunkLen - len(k1) - 1) ] + chunks[k1] chunks[k1] = [ c if len(c) >= chunkLen else c + " " * (chunkLen - len(c)) for c in chunks[k1] ] nrChunks = col // (chunkLen + 3) for i in range(0, len(chunks[k1]), nrChunks): result += " | ".join( chunks[k1][i:(i + nrChunks)]) + "\n" else: result += kk + ": " + v + " " + "-" * (col - len(k) - len(v) - 3) + "\n" return result def setTime(self, time): """Sets the time and alert all the LineAnalyzers that the time has changed :param time: the new value of the time """ if time != self.time: self.progressOut.reset() self.time = time for listener in self.timeListeners: listener.timeChanged() for nm in self.analyzers: self.analyzers[nm].timeChanged() self.checkTriggers() data = self.collectData() for listener in self.timeListeners: try: # make sure everyone gets a separate copy listener.setDataSet(deepcopy(data)) except AttributeError: # seems that the listener doesn't want the data pass def resetFile(self): """Propagate a reset to the actual analyzers""" for nm in self.analyzers: self.analyzers[nm].resetFile() for f in self.resetFileTriggers: f() def writeProgress(self, msg): """Write a message to the progress output""" self.progressOut(msg) def addTimeListener(self, listener): """:param listener: An object that is notified when the time changes. Has to implement a timeChanged method""" if not 'timeChanged' in dir(listener): error("Error. Object has no timeChanged-method:" + str(listener)) else: self.timeListeners.append(listener) def addResetFileTrigger(self, f): self.resetFileTriggers.append(f) def listAnalyzers(self): """:returns: A list with the names of the Analyzers""" return list(self.analyzers.keys()) def hasAnalyzer(self, name): """Is this LogLineAnalyzer name there""" return name in self.analyzers def getAnalyzer(self, name): """Get the LogLineAnalyzer name""" if name in self.analyzers: return self.analyzers[name] else: return None def addAnalyzer(self, name, obj): """Adds an analyzer obj - A LogLineAnalyzer name - the name of the analyzer""" obj.setParent(self) self.analyzers[name] = obj def analyzeLine(self, line): """Calls all the anlyzers for a line""" self.analyzedLines += 1 for nm in self.analyzers: self.analyzers[nm].doAnalysis(line) def analyze(self, fh): """Analyzes a file (one line at a time) fh - handle of the file""" while (self.line.read(fh)): self.analyzeLine(self.line.line) def goOn(self): """Checks with all the analyzers If one analyzer returns False it returns False""" result = True for nm in self.analyzers: # print nm,self.analyzers[nm].goOn() result = result and self.analyzers[nm].goOn() return result def getTime(self): """Gets the current time""" return str(self.time) def isPastTime(self, check): """Are we past a given Time?""" if check is None: return False try: t = float(self.getTime()) return t > check except ValueError: return False def setDirectory(self, d): """Sets the output directory for all the analyzers""" self.oDir = d for nm in self.analyzers: self.analyzers[nm].setDirectory(self.oDir) def getDirectory(self): """Gets the output directory""" return self.oDir def addTrigger(self, time, func, once=True, until=None): """Adds a trigger function that is to be called as soon as the simulation time exceeds a certain value :param time: the time at which the function should be triggered :param func: the trigger function :param once: Should this function be called once or at every time-step :param until: The time until which the trigger should be called""" data = {} data["time"] = float(time) data["func"] = func if until != None: data["until"] = float(until) once = False data["once"] = once self.timeTriggers.append(data) def checkTriggers(self): """Check for and execute the triggered functions""" remove = [] for i in range(len(self.timeTriggers)): t = self.timeTriggers[i] if t["time"] <= self.time: t["func"]() if t["once"]: remove.append(i) elif "until" in t: if t["until"] <= self.time: remove.append(i) remove.reverse() for i in remove: self.timeTriggers.pop(i)
class FoamLogAnalyzer(object): """Base class for all analyzers Administrates and calls a number of LogLineAnlayzers for each line""" def __init__(self,progress=False): """ @param progress: Print time progress on console? """ self.analyzers={} self.time="" self.oDir="" self.line=LineReader() self.timeListeners=[] self.timeTriggers=[] self.customExpr=re.compile("Custom([0-9]+)_(.+)") self.progressOut=None if progress: self.progressOut=ProgressOutput(stdout) tm=TimeLineAnalyzer(progress=progress) self.addAnalyzer("Time",tm) tm.addListener(self.setTime) def tearDown(self): """Remove reference to self in children (hoping to remove circular dependencies)""" for a in list(self.analyzers.values()): a.tearDown() a.setParent(None) def collectData(self): """Collect dictionaries of collected data (current state) from the analyzers @return: the dictionary""" result={} for nm in self.analyzers: data=self.analyzers[nm].getCurrentData() if len(data)>0: m=self.customExpr.match(nm) if m: if not "Custom" in result: result["Custom"]={} nr,name=m.groups() result["Custom"][name]=data # this will store custom data twice. But we'll keep it # for backward-compatibility result[nm]=data return result def setTime(self,time): """Sets the time and alert all the LineAnalyzers that the time has changed @param time: the new value of the time """ if time!=self.time: if self.progressOut: self.progressOut.reset() self.time=time for listener in self.timeListeners: listener.timeChanged() for nm in self.analyzers: self.analyzers[nm].timeChanged() self.checkTriggers() data=self.collectData() for listener in self.timeListeners: try: # make sure everyone gets a separate copy listener.setDataSet(deepcopy(data)) except AttributeError: # seems that the listener doesn't want the data pass def writeProgress(self,msg): """Write a message to the progress output""" if self.progressOut: self.progressOut(msg) def addTimeListener(self,listener): """@param listener: An object that is notified when the time changes. Has to implement a timeChanged method""" if not 'timeChanged' in dir(listener): error("Error. Object has no timeChanged-method:"+str(listener)) else: self.timeListeners.append(listener) def listAnalyzers(self): """@returns: A list with the names of the Analyzers""" return list(self.analyzers.keys()) def hasAnalyzer(self,name): """Is this LogLineAnalyzer name there""" return name in self.analyzers def getAnalyzer(self,name): """Get the LogLineAnalyzer name""" if name in self.analyzers: return self.analyzers[name] else: return None def addAnalyzer(self,name,obj): """Adds an analyzer obj - A LogLineAnalyzer name - the name of the analyzer""" obj.setParent(self) self.analyzers[name]=obj def analyzeLine(self,line): """Calls all the anlyzers for a line""" for nm in self.analyzers: self.analyzers[nm].doAnalysis(line) def analyze(self,fh): """Analyzes a file (one line at a time) fh - handle of the file""" while(self.line.read(fh)): self.analyzeLine(self.line.line) def goOn(self): """Checks with all the analyzers If one analyzer returns False it returns False""" result=True for nm in self.analyzers: # print nm,self.analyzers[nm].goOn() result=result and self.analyzers[nm].goOn() return result def getTime(self): """Gets the current time""" return str(self.time) def setDirectory(self,d): """Sets the output directory for all the analyzers""" self.oDir=d for nm in self.analyzers: self.analyzers[nm].setDirectory(self.oDir) def getDirectory(self): """Gets the output directory""" return self.oDir def addTrigger(self,time,func,once=True,until=None): """Adds a trigger function that is to be called as soon as the simulation time exceeds a certain value @param time: the time at which the function should be triggered @param func: the trigger function @param once: Should this function be called once or at every time-step @param until: The time until which the trigger should be called""" data={} data["time"]=float(time) data["func"]=func if until!=None: data["until"]=float(until) once=False data["once"]=once self.timeTriggers.append(data) def checkTriggers(self): """Check for and execute the triggered functions""" remove=[] for i in range(len(self.timeTriggers)): t=self.timeTriggers[i] if t["time"]<=self.time: t["func"]() if t["once"]: remove.append(i) elif "until" in t: if t["until"]<=self.time: remove.append(i) remove.reverse() for i in remove: self.timeTriggers.pop(i)
class FoamLogAnalyzer(object): """Base class for all analyzers Administrates and calls a number of LogLineAnlayzers for each line""" def __init__(self, progress=False): """ @param progress: Print time progress on console? """ self.analyzers = {} self.time = "" self.oDir = "" self.line = LineReader() self.timeListeners = [] self.timeTriggers = [] self.customExpr = re.compile("Custom([0-9]+)_(.+)") self.progressOut = None if progress: self.progressOut = ProgressOutput(stdout) tm = TimeLineAnalyzer(progress=progress) self.addAnalyzer("Time", tm) tm.addListener(self.setTime) def tearDown(self): """Remove reference to self in children (hoping to remove circular dependencies)""" for a in list(self.analyzers.values()): a.tearDown() a.setParent(None) def collectData(self): """Collect dictionaries of collected data (current state) from the analyzers @return: the dictionary""" result = {} for nm in self.analyzers: data = self.analyzers[nm].getCurrentData() if len(data) > 0: m = self.customExpr.match(nm) if m: if not "Custom" in result: result["Custom"] = {} nr, name = m.groups() result["Custom"][name] = data # this will store custom data twice. But we'll keep it # for backward-compatibility result[nm] = data return result def setTime(self, time): """Sets the time and alert all the LineAnalyzers that the time has changed @param time: the new value of the time """ if time != self.time: if self.progressOut: self.progressOut.reset() self.time = time for listener in self.timeListeners: listener.timeChanged() for nm in self.analyzers: self.analyzers[nm].timeChanged() self.checkTriggers() data = self.collectData() for listener in self.timeListeners: try: # make sure everyone gets a separate copy listener.setDataSet(deepcopy(data)) except AttributeError: # seems that the listener doesn't want the data pass def writeProgress(self, msg): """Write a message to the progress output""" if self.progressOut: self.progressOut(msg) def addTimeListener(self, listener): """@param listener: An object that is notified when the time changes. Has to implement a timeChanged method""" if not 'timeChanged' in dir(listener): error("Error. Object has no timeChanged-method:" + str(listener)) else: self.timeListeners.append(listener) def listAnalyzers(self): """@returns: A list with the names of the Analyzers""" return list(self.analyzers.keys()) def hasAnalyzer(self, name): """Is this LogLineAnalyzer name there""" return name in self.analyzers def getAnalyzer(self, name): """Get the LogLineAnalyzer name""" if name in self.analyzers: return self.analyzers[name] else: return None def addAnalyzer(self, name, obj): """Adds an analyzer obj - A LogLineAnalyzer name - the name of the analyzer""" obj.setParent(self) self.analyzers[name] = obj def analyzeLine(self, line): """Calls all the anlyzers for a line""" for nm in self.analyzers: self.analyzers[nm].doAnalysis(line) def analyze(self, fh): """Analyzes a file (one line at a time) fh - handle of the file""" while (self.line.read(fh)): self.analyzeLine(self.line.line) def goOn(self): """Checks with all the analyzers If one analyzer returns False it returns False""" result = True for nm in self.analyzers: # print nm,self.analyzers[nm].goOn() result = result and self.analyzers[nm].goOn() return result def getTime(self): """Gets the current time""" return str(self.time) def setDirectory(self, d): """Sets the output directory for all the analyzers""" self.oDir = d for nm in self.analyzers: self.analyzers[nm].setDirectory(self.oDir) def getDirectory(self): """Gets the output directory""" return self.oDir def addTrigger(self, time, func, once=True, until=None): """Adds a trigger function that is to be called as soon as the simulation time exceeds a certain value @param time: the time at which the function should be triggered @param func: the trigger function @param once: Should this function be called once or at every time-step @param until: The time until which the trigger should be called""" data = {} data["time"] = float(time) data["func"] = func if until != None: data["until"] = float(until) once = False data["once"] = once self.timeTriggers.append(data) def checkTriggers(self): """Check for and execute the triggered functions""" remove = [] for i in range(len(self.timeTriggers)): t = self.timeTriggers[i] if t["time"] <= self.time: t["func"]() if t["once"]: remove.append(i) elif "until" in t: if t["until"] <= self.time: remove.append(i) remove.reverse() for i in remove: self.timeTriggers.pop(i)
class FoamThread(Thread): """Thread running an OpenFOAM command The output of the command can be accessed in a thread-safe manner, line by line Designed to be used by the BasicRunner-class""" def __init__(self,cmdline,runner): """:param cmdline:cmdline - Command line of the OpenFOAM command :param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline=cmdline self.runner=runner self.output=None self.reader=LineReader(config().getboolean("SolverOutput","stripSpaces")) self.keyboardInterupted=False self.isLinux=False self.isDarwin=False self.isWindows=False self.threadPid=-1 self.who=RUSAGE_CHILDREN if uname()[0]=="Linux": self.isLinux=True self.linuxMaxMem=0 elif uname()[0]=="Darwin": self.isDarwin=True elif uname()[0]=="Windows": self.isWindows=True self.resStart=None self.resEnd=None self.timeStart=None self.timeEnd=None self.timerTime=5. self.stateLock=Lock() self.setState(False) self.status=None self.returncode=None self.lineLock=Lock() self.line="" self.stateLock.acquire() def run(self): """start the command""" # print "Starting ",self.cmdline self.resStart=getrusage(self.who) self.timeStart=time() if sys.version_info<(2,4): run=Popen4(self.cmdline) self.output=run.fromchild else: run=subprocess.Popen(shellExecutionPrefix()+self.cmdline, shell=True, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) self.output=run.stdout self.run=run self.threadPid=run.pid foamLogger().info("Started with PID %d" % self.threadPid) if self.isLinux: # print "Starting Timer" self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self]) self.timer.start() # print "Starting Timer" self.timer2=Timer(0.5*self.timerTime,checkForStopFile,args=[self]) self.timer2.start() self.hasSomethingToSay=True self.stateLock.release() try: # print "Waiting",time() self.status=run.wait() # Python 2.3 on Mac OS X never seems to reach this point # print "After wait",time() # print "Status:",self.status # to give a chance to read the remaining output if self.hasSomethingToSay: sleep(2.) while self.reader.read(self.output): print_("Unused output:",self.reader.line) except OSError: e = sys.exc_info()[1] # compatible with 2.x and 3.x print_("Exeption caught:",e) self.stopTimer() self.threadPid=-1 self.resEnd=getrusage(self.who) self.timeEnd=time() # print "End:",self.timeEnd # print "Returned",self.status self.getReturnCode() def getReturnCode(self): if sys.version_info<(2,4): # Don't know how to get the returncode from a Popen4-object self.returncode=0 else: self.returncode=self.run.returncode return self.returncode def stopTimer(self): if self.isLinux: self.timer.cancel() self.timer2.cancel() def read(self): """read another line from the output""" self.setState(self.reader.read(self.output)) self.lineLock.acquire() self.line=self.reader.line self.lineLock.release() def getLine(self): """gets the last line from the output""" self.lineLock.acquire() val=self.line self.lineLock.release() return val def interrupt(self): """A keyboard-interrupt is reported""" self.reader.wasInterupted=True self.setState(False) def setState(self,state): """sets the state of the thread (is there any more output)""" self.stateLock.acquire() self.hasSomethingToSay=state if not self.hasSomethingToSay and self.timeStart and self.reader.wasInterupted: self.keyboardInterupted=self.reader.keyboardInterupted if self.threadPid>0: msg="Killing PID %d" % self.threadPid print_(msg) foamLogger().warning(msg) try: kill(self.threadPid,signal.SIGKILL) except OSError: warning("Process",self.threadPid,"was already dead") # print "Set: ",state self.stateLock.release() def check(self): """:return: False if there is no more output of the command""" self.stateLock.acquire() state=self.hasSomethingToSay # print "Get: ",state self.stateLock.release() return state def cpuTime(self): """:return: number of seconds CPU-Time used""" return self.cpuUserTime()+self.cpuSystemTime() def cpuUserTime(self): """:return: number of seconds CPU-Time used in user mode""" if self.resEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.resEnd=getrusage(self.who) if self.resStart==None or self.resEnd==None: return 0 else: return self.resEnd.ru_utime-self.resStart.ru_utime def cpuSystemTime(self): """:return: number of seconds CPU-Time used in system mode""" if self.resEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.resEnd=getrusage(self.who) if self.resStart==None or self.resEnd==None: return 0 else: return self.resEnd.ru_stime-self.resStart.ru_stime def usedMemory(self): """:return: maximum resident set size in MegaByte""" scale=1024.*1024. if self.isLinux: return self.linuxMaxMem/scale if self.resStart==None or self.resEnd==None: return 0. else: return getpagesize()*(self.resEnd.ru_maxrss-self.resStart.ru_maxrss)/scale def wallTime(self): """:return: the wall-clock-time needed by the process""" if self.timeEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.timeEnd=time() self.timeEnd=time() # print "Wall:",self.timeEnd,self.timeStart if self.timeStart==None or self.timeEnd==None: return 0 else: return self.timeEnd-self.timeStart
class FoamThread(Thread): """Thread running an OpenFOAM command The output of the command can be accessed in a thread-safe manner, line by line Designed to be used by the BasicRunner-class""" def __init__(self,cmdline,runner): """:param cmdline:cmdline - Command line of the OpenFOAM command :param runner: the Runner-object that started this thread""" Thread.__init__(self) self.cmdline=cmdline self.runner=runner self.output=None self.reader=LineReader(config().getboolean("SolverOutput","stripSpaces")) self.keyboardInterupted=False self.isLinux=False self.isDarwin=False self.isWindows=False self.threadPid=-1 self.who=RUSAGE_CHILDREN if uname()[0]=="Linux": self.isLinux=True self.linuxMaxMem=0 elif uname()[0]=="Darwin": self.isDarwin=True elif uname()[0]=="Windows": self.isWindows=True self.resStart=None self.resEnd=None self.timeStart=None self.timeEnd=None self.timerTime=5. self.stateLock=Lock() self.setState(False) self.status=None self.returncode=None self.lineLock=Lock() self.line="" self.stateLock.acquire() def run(self): """start the command""" # print "Starting ",self.cmdline self.resStart=getrusage(self.who) self.timeStart=time() if sys.version_info<(2,4): run=Popen4(self.cmdline) self.output=run.fromchild else: run=subprocess.Popen(shellExecutionPrefix()+self.cmdline, shell=True, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) self.output=run.stdout self.run=run self.threadPid=run.pid foamLogger().info("Started with PID %d" % self.threadPid) if self.isLinux: # print "Starting Timer" self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self]) self.timer.start() # print "Starting Timer" self.timer2=Timer(0.5*self.timerTime,checkForStopFile,args=[self]) self.timer2.start() self.hasSomethingToSay=True self.stateLock.release() try: # print "Waiting",time() self.status=run.wait() # Python 2.3 on Mac OS X never seems to reach this point # print "After wait",time() # print "Status:",self.status # to give a chance to read the remaining output if self.hasSomethingToSay: sleep(2.) while self.reader.read(self.output): print_("Unused output:",self.reader.line) except OSError: e = sys.exc_info()[1] # compatible with 2.x and 3.x print_("Exeption caught:",e) self.stopTimer() self.threadPid=-1 self.resEnd=getrusage(self.who) self.timeEnd=time() # print "End:",self.timeEnd # print "Returned",self.status self.getReturnCode() def getReturnCode(self): if sys.version_info<(2,4): # Don't know how to get the returncode from a Popen4-object self.returncode=0 else: self.returncode=self.run.returncode return self.returncode def stopTimer(self): if self.isLinux: self.timer.cancel() self.timer2.cancel() def read(self): """read another line from the output""" self.setState(self.reader.read(self.output)) self.lineLock.acquire() self.line=self.reader.line self.lineLock.release() def getLine(self): """gets the last line from the output""" self.lineLock.acquire() val=self.line self.lineLock.release() return val def interrupt(self): """A keyboard-interrupt is reported""" # print "Interrupt" self.reader.wasInterupted=True self.setState(False) def setState(self,state): """sets the state of the thread (is there any more output)""" self.stateLock.acquire() self.hasSomethingToSay=state if not self.hasSomethingToSay and self.timeStart and self.reader.wasInterupted: self.keyboardInterupted=self.reader.keyboardInterupted if self.threadPid>0: msg="Killing PID %d" % self.threadPid print_(msg) foamLogger().warning(msg) try: kill(self.threadPid,signal.SIGKILL) except OSError: warning("Process",self.threadPid,"was already dead") # print "Set: ",state self.stateLock.release() def check(self): """:return: False if there is no more output of the command""" self.stateLock.acquire() state=self.hasSomethingToSay # print "Get: ",state self.stateLock.release() return state def cpuTime(self): """:return: number of seconds CPU-Time used""" return self.cpuUserTime()+self.cpuSystemTime() def cpuUserTime(self): """:return: number of seconds CPU-Time used in user mode""" if self.resEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.resEnd=getrusage(self.who) if self.resStart==None or self.resEnd==None: return 0 else: return self.resEnd.ru_utime-self.resStart.ru_utime def cpuSystemTime(self): """:return: number of seconds CPU-Time used in system mode""" if self.resEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.resEnd=getrusage(self.who) if self.resStart==None or self.resEnd==None: return 0 else: return self.resEnd.ru_stime-self.resStart.ru_stime def usedMemory(self): """:return: maximum resident set size in MegaByte""" scale=1024.*1024. if self.isLinux: return self.linuxMaxMem/scale if self.resStart==None or self.resEnd==None: return 0. else: return getpagesize()*(self.resEnd.ru_maxrss-self.resStart.ru_maxrss)/scale def wallTime(self): """:return: the wall-clock-time needed by the process""" if self.timeEnd==None: # and self.isDarwin: # Mac OS X needs this (Ubuntu too?) self.timeEnd=time() self.timeEnd=time() # print "Wall:",self.timeEnd,self.timeStart if self.timeStart==None or self.timeEnd==None: return 0 else: return self.timeEnd-self.timeStart
class BasicWatcher(object): """Base class for watching the output of commands Works like the UNIX-command 'tail -f <file>': the last lines of the file are output. If the file grows then these lines are output as they arrive""" def __init__(self,filenames, silent=False, tailLength=1000, sleep=0.1, follow=True): """:param filename: name of the logfile to watch :param silent: if True no output is sent to stdout :param tailLength: number of bytes at the end of the fail that should be output. :param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis :param sleep: interval to sleep if no line is returned""" if type(filenames) is list: meshTimes=[] createMesh="Create mesh for time = " for fName in filenames: meshTime=None with open(fName) as f: for l in f.readlines()[:100]: if l.find(createMesh)==0: meshTime=float(l[len(createMesh):]) break meshTimes.append((fName,meshTime)) meshTimes.sort(key=lambda x:1e50 if x[1] is None else x[1]) filenames=[m[0] for m in meshTimes] self.filename=filenames[0] self.nextFiles=filenames[1:] self.changeTimes=[m[1] for m in meshTimes[1:]] else: self.filename=filenames self.nextFiles=[] self.changeTimes=[] self._changeFileHooks=[] self.silent=silent self.tail=tailLength self.sleep=sleep self.follow=follow self.isTailing=False if not path.exists(self.filename): print_("Error: Logfile ",self.filename,"does not exist") self.reader=LineReader(config().getboolean("SolverOutput","stripSpaces")) def getSize(self,filename): """:return: the current size (in bytes) of the file""" return os.stat(filename)[stat.ST_SIZE] def addChangeFileHook(self,func): self._changeFileHooks.append(func) def changeFile(self,filename): currSize=self.getSize(filename) fn,ext=path.splitext(filename) if ext=='.gz': fh=gzip.open(filename) else: fh=open(filename) for f in self._changeFileHooks: f() return fh,currSize def start(self): """Reads the file and does the processing""" fh,currSize=self.changeFile(self.filename) switchTime=None if len(self.changeTimes)==0 else self.changeTimes[0] self.changeTimes=self.changeTimes[1:] self.startHandle() while self.follow or currSize>self.reader.bytesRead() or len(self.nextFiles)>0: if not currSize>self.reader.bytesRead() or self.analyzer.isPastTime(switchTime): if len(self.nextFiles)>0: print_("\n\nSwitching from logfile",self.filename, "to",self.nextFiles[0],"\n\n") self.filename=self.nextFiles[0] self.nextFiles=self.nextFiles[1:] fh,currSize=self.changeFile(self.filename) switchTime=None if len(self.changeTimes)==0 else self.changeTimes[0] self.changeTimes=self.changeTimes[1:] self.reader.reset() self.analyzer.resetFile() if currSize==0: continue else: if not self.follow: break try: status=self.reader.read(fh) if status: line=self.reader.line if (currSize-self.reader.bytesRead())<=self.tail: if not self.isTailing: self.isTailing=True self.timeHandle() self.tailingHandle() if not self.silent: print_(line) self.lineHandle(line) else: if self.reader.userSaidStop(): break sleep(self.sleep) except KeyboardInterrupt: print_("Watcher: Keyboard interrupt") break self.stopHandle() fh.close() def startHandle(self): """to be called before the program is started""" pass def stopHandle(self): """called after the program has stopped""" pass def tailingHandle(self): """called when the first line is output""" pass def lineHandle(self,line): """called every time a new line is read""" pass
class BasicWatcher(object): """Base class for watching the output of commands Works like the UNIX-command 'tail -f <file>': the last lines of the file are output. If the file grows then these lines are output as they arrive""" def __init__(self, filename, silent=False, tailLength=1000, sleep=0.1, follow=True): """:param filename: name of the logfile to watch :param silent: if True no output is sent to stdout :param tailLength: number of bytes at the end of the fail that should be output. :param follow: if the end of the file is reached wait for further input Because data is output on a per-line-basis :param sleep: interval to sleep if no line is returned""" self.filename = filename self.silent = silent self.tail = tailLength self.sleep = sleep self.follow = follow self.isTailing = False if not path.exists(self.filename): print_("Error: Logfile ", self.filename, "does not exist") self.reader = LineReader(config().getboolean("SolverOutput", "stripSpaces")) def getSize(self): """:return: the current size (in bytes) of the file""" return os.stat(self.filename)[stat.ST_SIZE] def start(self): """Reads the file and does the processing""" currSize = self.getSize() fn, ext = path.splitext(self.filename) if ext == '.gz': fh = gzip.open(self.filename) else: fh = open(self.filename) self.startHandle() while self.follow or currSize > self.reader.bytesRead(): try: status = self.reader.read(fh) if status: line = self.reader.line if (currSize - self.reader.bytesRead()) <= self.tail: if not self.isTailing: self.isTailing = True self.timeHandle() self.tailingHandle() if not self.silent: print_(line) self.lineHandle(line) else: if self.reader.userSaidStop(): break sleep(self.sleep) except KeyboardInterrupt: print_("Watcher: Keyboard interrupt") break self.stopHandle() fh.close() def startHandle(self): """to be called before the program is started""" pass def stopHandle(self): """called after the program has stopped""" pass def tailingHandle(self): """called when the first line is output""" pass def lineHandle(self, line): """called every time a new line is read""" pass
def __startProcess(self): l = LineReader(False) self.openFile() return l