1
2 """Working with a directory of timelines
3
4 Currently not optimal as it reads the files more often than necessary"""
5
6 from os import path,listdir
7
8 from PyFoam.Error import error,warning
9 import math
10
11 try:
12 from sys.float_info import max as float_maximum
13 except ImportError:
14
15 float_maximum=1e301
16
17 from PyFoam.Basics.SpreadsheetData import SpreadsheetData
18
19 from PyFoam.ThirdParty.six import PY3
20
21 if PY3:
22 from functools import reduce
23
25 """A directory of sampled times"""
26
27 - def __init__(self,case,dirName="probes",writeTime=None):
28 """@param case: The case directory
29 @param dirName: Name of the directory with the timelines
30 @param writeTime: The write time-directory where the data in question is to be plotted"""
31
32 self.dir=path.join(case,dirName)
33 self.writeTimes=[]
34
35 nearest=None
36
37 for d in listdir(self.dir):
38 if path.isdir(path.join(self.dir,d)):
39 try:
40 v=float(d)
41 self.writeTimes.append(d)
42 if writeTime:
43 if nearest==None:
44 nearest=d
45 else:
46 if abs(float(writeTime)-v)<abs(float(writeTime)-float(nearest)):
47 nearest=d
48 except ValueError:
49 pass
50
51 self.writeTimes.sort(key=float)
52 if nearest==None:
53 self.usedTime=self.writeTimes[0]
54 else:
55 self.usedTime=nearest
56
57 self.dir=path.join(self.dir,self.usedTime)
58
59 self.values=[]
60 self.vectors=[]
61 for v in listdir(self.dir):
62 if v[0]=='.':
63 continue
64 tv=TimelineValue(self.dir,v,self.usedTime)
65 if tv.isValid:
66 self.values.append(v)
67 if tv.isVector:
68 self.vectors.append(v)
69
70 self.allPositions=None
71
75
81
84
87
89 """Returns all the found positions"""
90
91 if self.allPositions==None:
92 positions=[]
93 first=True
94
95 for t in self:
96 for v in t.positions:
97 if v not in positions:
98 if first:
99 positions.append(v)
100 else:
101 error("Found positions",t.positions,"are inconsistent with previous",positions)
102 if first:
103 self.positionIndex=t.positionIndex
104 first=False
105 self.allPositions=positions
106
107 return self.allPositions
108
110 """Return the range of possible times"""
111 minTime=1e80
112 maxTime=-1e80
113
114 for v in self:
115 mi,ma=v.timeRange()
116 minTime=min(mi,minTime)
117 maxTime=max(ma,maxTime)
118
119 return minTime,maxTime
120
122 """Get Timeline sets
123 @param value: name of the value. All
124 if unspecified
125 @param position: name of the position of the value. All
126 if unspecified"""
127
128 if value==None:
129 value=self.values
130 if position==None:
131 position=self.positions()
132
133 sets=[]
134
135 for v in value:
136 for p in position:
137 fName=path.join(self.dir,v)
138 if not "positionIndex" in self:
139 self.positions()
140 pos=self.positionIndex[self.positions().index(p)]
141 if v in self.vectors:
142 fName="< tr <%s -d '()'" %fName
143 pos=pos*3
144 if vectorMode=="x":
145 pass
146 elif vectorMode=="y":
147 pos+=1
148 elif vectorMode=="z":
149 pos+=2
150 elif vectorMode=="mag":
151 pos+=2
152 pos="(sqrt($%d*$%d+$%d*$%d+$%d*$%d))" % (pos,pos,
153 pos+1,pos+1,
154 pos+2,pos+2)
155 else:
156 error("Unsupported vector mode",vectorMode,"for",value)
157 try:
158 sets.append((fName,v,p,pos,TimelineValue(self.dir,v,self.usedTime)))
159 except IOError:
160
161 pass
162
163 return sets
164
165 - def getData(self,times,value=None,position=None,vectorMode=None):
166 """Get data that mstches the given times most closely
167 @param times: a list with times
168 @param value: name of the value. All
169 if unspecified
170 @param position: name of the position of the value. All
171 if unspecified
172 @param vectorMode: which component of the vector to use"""
173
174 if value==None:
175 value=self.values
176 if position==None:
177 position=self.positions()
178
179 sets=[]
180 posIndex=[]
181 for p in position:
182 posIndex.append(self.positions().index(p))
183
184 for v in value:
185 val=TimelineValue(self.dir,v,self.usedTime)
186 data=val.getData(times,vectorMode=vectorMode)
187 for i,t in enumerate(times):
188 used=[]
189 for p in posIndex:
190 used.append(data[i][p])
191
192 sets.append((v,t,used))
193
194 return sets
195
197 """A file with one timelined value"""
198
200 """@param sDir: The timeline-dir
201 @param val: the value
202 @param time: the timename"""
203
204 self.isValid=False
205 self.val=val
206 self.time=time
207 self.file=path.join(sDir,val)
208 poses=[]
209
210 self.isVector=False
211
212 data=open(self.file)
213 l1=data.readline()
214 if len(l1)<1 or l1[0]!='#':
215 error("Data file",self.file,"has no description of the fields")
216 l2=data.readline()
217
218 self._isProbe=True
219 try:
220 if l2[0]!='#':
221
222 poses=l1[1:].split()[1:]
223 firstData=l2
224 self._isProbe=False
225 else:
226
227 l3=data.readline()
228 x=l1[1:].split()[1:]
229 y=l2[1:].split()[1:]
230 z=l3[1:].split()[1:]
231 for i in range(len(x)):
232 poses.append("(%s %s %s)" % (x[i],y[i],z[i]))
233 data.readline()
234 firstData=data.readline()
235 except IndexError:
236 warning("Could not determine the type of",self.file)
237 return
238
239 self.positions=[]
240 self.positionIndex=[]
241 if len(poses)+1==len(firstData.split()):
242
243 for i,v in enumerate(firstData.split()[1:]):
244 if abs(float(v))<float_maximum:
245 self.positions.append(poses[i])
246 self.positionIndex.append(i)
247 elif 3*len(poses)+1==len(firstData.split()):
248 self.isVector=True
249 for i,v in enumerate(firstData.split()[2::3]):
250 if abs(float(v))<float_maximum:
251 self.positions.append(poses[i])
252 self.positionIndex.append(i)
253 else:
254 warning(self.file,
255 "is an unsupported type (neither vector nor scalar). Skipping")
256 return
257
258 self.cache={}
259 self.isValid=True
260
262 if self.isVector:
263 vect=" (vector)"
264 else:
265 vect=""
266
267 return "TimelineData of %s%s on %s at t=%s " % (self.val,vect,str(self.positions),self.time)
268
270 """Is this a probe-file"""
271 return self._isProbe
272
274 """Range of times"""
275 lines=open(self.file).readlines()
276 for l in lines:
277 v=l.split()
278 if v[0][0]!='#':
279 minRange=float(v[0])
280 break
281 lines.reverse()
282 for l in lines:
283 v=l.split()
284 if len(v)>=len(self.positions)+1:
285 maxRange=float(v[0])
286 break
287
288 return minRange,maxRange
289
290 - def getData(self,times,vectorMode=None):
291 """Get the data values that are nearest to the actual times"""
292 if self.isVector and vectorMode==None:
293 vectorMode="mag"
294
295 dist=len(times)*[1e80]
296 data=len(times)*[len(self.positions)*[1e80]]
297
298 lines=open(self.file).readlines()
299
300 for l in lines:
301 v=l.split()
302 if v[0][0]!='#':
303 try:
304 time=float(v[0])
305 vals=[x.replace('(','').replace(')','') for x in v[1:]]
306 for i,t in enumerate(times):
307 if abs(t-time)<dist[i]:
308 dist[i]=abs(t-time)
309 data[i]=vals
310 except ValueError:
311 pass
312 result=[]
313 for d in data:
314 tmp=[]
315 if self.isVector:
316 for p in range(len(self.positions)):
317 if vectorMode=="x":
318 tmp.append(float(d[p]))
319 elif vectorMode=="y":
320 tmp.append(float(d[p+1]))
321 elif vectorMode=="z":
322 tmp.append(float(d[p+2]))
323 elif vectorMode=="mag":
324 tmp.append(math.sqrt(reduce(lambda a,b:a+b,[float(v)**2 for v in d[p:p+3]],0)))
325 else:
326 error("Unknown vector mode",vectorMode)
327 else:
328 for v in d:
329 if abs(float(v))<1e40:
330 tmp.append(float(v))
331 result.append(tmp)
332
333 return result
334
354
355
356