Source code for PyFoam.RunDictionary.TimelineDirectory

#  ICE Revision: $Id:$
"""Working with a directory of timelines

Currently not optimal as it reads the files more often than necessary"""

from os import path,listdir

from PyFoam.Error import error,warning
import math

try:
    from sys.float_info import max as float_maximum
except ImportError:
    # needed py python2.5
    float_maximum=1e301

from PyFoam.Basics.SpreadsheetData import SpreadsheetData

from PyFoam.ThirdParty.six import PY3

if PY3:
    from functools import reduce

[docs]class TimelineDirectory(object): """A directory of sampled times""" def __init__(self,case=None,dirName="probes",writeTime=None): """:param case: The case directory :param dirName: Name of the directory with the timelines :param writeTime: The write time-directory where the data in question is to be plotted""" if case is None: self.dir=dirName else: self.dir=path.join(case,dirName) self.writeTimes=[] nearest=None for d in listdir(self.dir): if path.isdir(path.join(self.dir,d)): try: v=float(d) self.writeTimes.append(d) if writeTime: if nearest==None: nearest=d else: if abs(float(writeTime)-v)<abs(float(writeTime)-float(nearest)): nearest=d except ValueError: pass self.writeTimes.sort(key=float) if nearest==None: self.usedTime=self.writeTimes[0] else: self.usedTime=nearest self.dir=path.join(self.dir,self.usedTime) self.values=[] self.vectors=[] for v in listdir(self.dir): if v[0]=='.': continue # Skip dot-files tv=TimelineValue(self.dir,v,self.usedTime) if tv.isValid: self.values.append(v) if tv.isVector: self.vectors.append(v) self.allPositions=None def __iter__(self): for t in self.values: yield TimelineValue(self.dir,t,self.usedTime) def __getitem__(self,value): if value in self: return TimelineValue(self.dir,value,self.usedTime) else: raise KeyError(value) def __contains__(self,value): return value in self.values def __len__(self): return len(self.values)
[docs] def positions(self): """Returns all the found positions""" if self.allPositions==None: positions=[] first=True for t in self: for v in t.positions: if v not in positions: if first: positions.append(v) else: error("Found positions",t.positions,"are inconsistent with previous",positions) if first: self.positionIndex=t.positionIndex first=False self.allPositions=positions return self.allPositions
[docs] def timeRange(self): """Return the range of possible times""" minTime=1e80 maxTime=-1e80 for v in self: mi,ma=v.timeRange() minTime=min(mi,minTime) maxTime=max(ma,maxTime) return minTime,maxTime
[docs] def getDataLocation(self,value=None,position=None,vectorMode=None): """Get Timeline sets :param value: name of the value. All if unspecified :param position: name of the position of the value. All if unspecified""" if value==None: value=self.values if position==None: position=self.positions() sets=[] for v in value: for p in position: fName=path.join(self.dir,v) if not "positionIndex" in self: self.positions() pos=self.positionIndex[self.positions().index(p)] if v in self.vectors: fName="< tr <%s -d '()'" %fName pos=pos*3 if vectorMode=="x": pass elif vectorMode=="y": pos+=1 elif vectorMode=="z": pos+=2 elif vectorMode=="mag": pos+=2 pos="(sqrt($%d*$%d+$%d*$%d+$%d*$%d))" % (pos,pos, pos+1,pos+1, pos+2,pos+2) else: error("Unsupported vector mode",vectorMode,"for",value) try: sets.append((fName,v,p,pos,TimelineValue(self.dir,v,self.usedTime))) except IOError: # seems like the file/field is not there pass return sets
[docs] def getData(self,times,value=None,position=None,vectorMode=None): """Get data that mstches the given times most closely :param times: a list with times :param value: name of the value. All if unspecified :param position: name of the position of the value. All if unspecified :param vectorMode: which component of the vector to use""" if value==None: value=self.values if position==None: position=self.positions() sets=[] posIndex=[] for p in position: posIndex.append(self.positions().index(p)) for v in value: val=TimelineValue(self.dir,v,self.usedTime) data=val.getData(times,vectorMode=vectorMode) for i,t in enumerate(times): used=[] for p in posIndex: used.append(data[i][p]) sets.append((v,t,used)) return sets
[docs]class TimelineValue(object): """A file with one timelined value""" def __init__(self,sDir,val,time): """:param sDir: The timeline-dir :param val: the value :param time: the timename""" self.isValid=False self.val=val self.time=time self.file=path.join(sDir,val) poses=[] self.isVector=False data=open(self.file) l1=data.readline() if len(l1)<1 or l1[0]!='#': error("Data file",self.file,"has no description of the fields") l2=data.readline() self._isProbe=True try: if l2[0]!='#': # Not a probe-file. The whole description is in the first line poses=l1[1:].split()[1:] firstData=l2 self._isProbe=False else: import re newProbe=re.compile(r"# Probe [0-9]+ (\(.+ .+ .+\))") if newProbe.match(l1): probeStrings=[l1] while newProbe.match(l2): probeStrings.append(l2) l2=data.readline() probeNrString=l2 probeTimeString=data.readline() poses=[newProbe.match(l).group(1) for l in probeStrings] if probeNrString[0]!="#" or probeTimeString[0]!="#": warning("This does not seem to be the format we were lookin for") else: # probe-file so we need one more line l3=data.readline() x=l1[1:].split()[1:] y=l2[1:].split()[1:] z=l3[1:].split()[1:] for i in range(len(x)): poses.append("(%s %s %s)" % (x[i],y[i],z[i])) data.readline() firstData=data.readline() except IndexError: warning("Could not determine the type of",self.file) return self.positions=[] self.positionIndex=[] if len(poses)+1==len(firstData.split()): #scalar for i,v in enumerate(firstData.split()[1:]): try: if abs(float(v))<float_maximum: self.positions.append(poses[i]) self.positionIndex.append(i) except ValueError: # Assuming string self.positions.append(poses[i]) self.positionIndex.append(i) elif 3*len(poses)+1==len(firstData.split()): self.isVector=True for i,v in enumerate(firstData.split()[2::3]): if abs(float(v))<float_maximum: self.positions.append(poses[i]) self.positionIndex.append(i) else: warning(self.file, "is an unsupported type (neither vector nor scalar). Skipping") return self.cache={} self.isValid=True def __repr__(self): if self.isVector: vect=" (vector)" else: vect="" return "TimelineData of %s%s on %s at t=%s " % (self.val,vect,str(self.positions),self.time)
[docs] def isProbe(self): """Is this a probe-file""" return self._isProbe
[docs] def timeRange(self): """Range of times""" lines=open(self.file).readlines() for l in lines: v=l.split() if v[0][0]!='#': minRange=float(v[0]) break lines.reverse() for l in lines: v=l.split() if len(v)>=len(self.positions)+1: maxRange=float(v[0]) break return minRange,maxRange
[docs] def getData(self,times,vectorMode=None): """Get the data values that are nearest to the actual times""" if self.isVector and vectorMode==None: vectorMode="mag" dist=len(times)*[1e80] data=len(times)*[len(self.positions)*[1e80]] lines=open(self.file).readlines() for l in lines: v=l.split() if v[0][0]!='#': try: time=float(v[0]) vals=[x.replace('(','').replace(')','') for x in v[1:]] for i,t in enumerate(times): if abs(t-time)<dist[i]: dist[i]=abs(t-time) data[i]=vals except ValueError: pass result=[] for d in data: tmp=[] if self.isVector: for p in range(len(self.positions)): if vectorMode=="x": tmp.append(float(d[p])) elif vectorMode=="y": tmp.append(float(d[p+1])) elif vectorMode=="z": tmp.append(float(d[p+2])) elif vectorMode=="mag": tmp.append(math.sqrt(reduce(lambda a,b:a+b,[float(v)**2 for v in d[p:p+3]],0))) else: error("Unknown vector mode",vectorMode) else: for v in d: try: if abs(float(v))<1e40: tmp.append(float(v)) except ValueError: tmp.append(v) result.append(tmp) return result
def __call__(self,addTitle=True): """Return the data as a SpreadsheetData-object""" def safeFloat(v): try: return float(v) except ValueError: return v lines=open(self.file).readlines() data=[] for l in lines: v=l.split() if v[0][0]!='#': data.append([safeFloat(x.replace('(','').replace(')','')) for x in v]) names=["time"] if self.isVector: for p in self.positions: names+=[p+" x",p+" y",p+" z"] else: names+=self.positions return SpreadsheetData(data=data, names=names, title="%s_t=%s" % (self.val,self.time) if addTitle else None)
# Should work with Python3 and Python2