1
2 """Working with a directory of samples"""
3
4 from os import path,listdir
5 from PyFoam.Error import error
6 import math
7 import re
8
9 from PyFoam.Basics.SpreadsheetData import SpreadsheetData
10
12 """A directory of sampled times"""
13
14 - def __init__(self,
15 case,
16 dirName="samples",
17 postfixes=[],
18 prefixes=[]):
19 """@param case: The case directory
20 @param dirName: Name of the directory with the samples
21 @param postfixes: list of possible extensions to a field name of the form
22 name_postfix to help splitting such field names.
23 @param prefixes: list of possible extensions to a field name of the form
24 prefix_name to help splitting such field names"""
25
26 self.dir=path.join(case,dirName)
27 self.times=[]
28
29 self.prefixes=prefixes
30 self.postfixes=postfixes
31
32 for d in listdir(self.dir):
33 if path.isdir(path.join(self.dir,d)):
34 try:
35 float(d)
36 self.times.append(d)
37 except ValueError:
38 pass
39
40 self.times.sort(self.sorttimes)
41
43 return len(self.times)
44
46 for t in self.times:
47 yield SampleTime(self.dir,
48 t,
49 prefixes=self.prefixes,
50 postfixes=self.postfixes)
51
53 if time in self:
54 return SampleTime(self.dir,
55 time,
56 prefixes=self.prefixes,
57 postfixes=self.postfixes)
58 else:
59 raise KeyError,time
60
62 return time in self.times
63
65 """Sort function for the solution files"""
66 if(float(x)==float(y)):
67 return 0
68 elif float(x)<float(y):
69 return -1
70 else:
71 return 1
72
85
98
99 - def getData(self,line=None,value=None,time=None,note=""):
100 """Get Sample sets
101 @param line: name of the line. All
102 if unspecified
103 @param value: name of the sampled value. All
104 if unspecified
105 @param time: times for which the samples are to be got. All
106 if unspecified
107 @param note: A short annotation (for plots)"""
108
109 if line==None:
110 line=self.lines()
111 if value==None:
112 value=self.values()
113 if time==None:
114 time=self.times
115
116 sets=[]
117
118 for t in time:
119 for l in line:
120 for v in value:
121 try:
122 d=self[t][(l,v)]
123 d.note=note
124 sets.append(d)
125 except KeyError:
126 pass
127
128 return sets
129
131 """A directory with one sampled time"""
132
133 - def __init__(self,
134 sDir,
135 time,
136 postfixes=[],
137 prefixes=[]):
138 """@param sDir: The sample-dir
139 @param time: the timename
140 @param postfixes: list of possible extensions to a field name of the form
141 name_postfix to help splitting such field names.
142 @param prefixes: list of possible extensions to a field name of the form
143 prefix_name to help splitting such field names"""
144
145 self.dir=path.join(sDir,time)
146 self.lines=[]
147 self.values=[]
148
149 self.prefixes=prefixes
150 self.postfixes=postfixes
151
152 self.__valueNames=None
153
154 for f in listdir(self.dir):
155 if f[0]=='.' or f[-1]=='~' or f.find(".")<0:
156 continue
157 nm=self.extractLine(f)
158 vals=self.extractValues(f)
159 if nm not in self.lines:
160 self.lines.append(nm)
161 for v in vals:
162 if v not in self.values:
163 self.values.append(v)
164
165 self.lines.sort()
166 self.values.sort()
167
168 self.cache={}
169
171 """Extract the name of the line from a filename"""
172 return fName.split("_")[0]
173
175 """Extracts the names of the contained Values from a filename"""
176
177 def preUnder(m):
178 return "&"+m.group(1)+m.group(2)
179 def postUnder(m):
180 return m.group(1)+m.group(2)+"&"
181
182 for p in self.prefixes:
183 fName=re.sub("([_&.]|^)("+p+")_",postUnder,fName)
184 for p in self.postfixes:
185 fName=re.sub("_("+p+")([_&.]|$)",preUnder,fName)
186
187 self.__valueNames=[]
188 try:
189 tmp=fName.split("_")[1:]
190 tmp[-1]=tmp[-1].split(".")[0]
191
192 for t in tmp:
193 self.__valueNames.append(t.replace("&","_"))
194 except IndexError:
195 pass
196
197 return self.__valueNames
198
200 """Get the data for a value on a specific line
201 @param key: A tuple with the line-name and the value-name
202 @returns: A SampleData-object"""
203
204 if key in self.cache:
205 return self.cache[key]
206
207 line,val=key
208 if line not in self.lines or val not in self.values:
209 raise KeyError,key
210
211 fName=None
212
213 for f in listdir(self.dir):
214 if line==self.extractLine(f) and val in self.extractValues(f):
215 fName=f
216 break
217
218 if fName==None:
219 error("Can't find a file for the line",line,"and the value",val,"in the directory",self.dir)
220
221 first=True
222 col0=[]
223 data=[]
224
225 for l in open(path.join(self.dir,fName)).readlines():
226 tmp=l.split()
227 if first:
228 first=False
229 vector,index=self.determineIndex(fName,val,tmp)
230
231 col0.append(float(tmp[0]))
232 try:
233 if vector:
234 data.append(tuple(map(float,tmp[index:index+3])))
235 else:
236 data.append(float(tmp[index]))
237 except IndexError:
238 raise KeyError(key)
239
240 self.cache[key]=SampleData(fName=path.join(self.dir,fName),
241 name=val,
242 index=index,
243 col0=col0,
244 data=data)
245
246 return self.cache[key]
247
249 """Determines the index of the data from the filename and a dataset
250 @param fName: name of the file
251 @param vName: Name of the quantity
252 @param data: A list with the data
253 @returns: A tuple of a boolean (whether the data is supposed to be
254 a vector or a scalar) and an integer (the index of the data set -
255 or the first component of the vector"""
256
257 vals=self.extractValues(fName)
258 if len(vals)+1==len(data):
259 vector=False
260 elif len(vals)*3+1==len(data):
261 vector=True
262 else:
263 error("The data in file",fName,"is neither vector nor scalar:",data)
264
265 index=vals.index(vName)
266 if vector:
267 index=index*3+1
268 else:
269 index=index+1
270
271 return vector,index
272
274 """Data from a sample-set"""
275
276 - def __init__(self,fName,name,index,col0,data,note=""):
277 """@param fName: Name of the file
278 @param name: Name of the value
279 @param index: Index of the data in the file
280 @param col0: Values that identify the data (the location)
281 @param data: The actual data"""
282
283 self.file=fName
284 self.col0=col0
285 self.data=data
286 self.name=name
287 self.index=index
288 self.note=note
289
291 if self.isVector():
292 vect=" (vector)"
293 else:
294 vect=""
295
296 return "SampleData of %s%s on %s at t=%s " % (self.name,vect,self.line(),self.time())
297
299 """Get the line of the sample"""
300 return path.basename(self.file).split("_")[0]
301
303 """Get the time of the sample (as a string)"""
304 return path.basename(path.dirname(self.file))
305
307 """Is this vector or scalar data?"""
308 if type(self.data[0])==tuple:
309 return True
310 else:
311 return False
312
313 - def range(self,component=None):
318
320 """Range of the data domain"""
321 return (min(self.col0),max(self.col0))
322
324 """Return the data as a number of single scalars.
325 @param component: If None for vectors the absolute value is taken.
326 else the number of the component"""
327
328 if self.isVector():
329 data=[]
330 if component==None:
331 for d in self.data:
332 data.append(math.sqrt(d[0]*d[0]+d[1]*d[1]+d[2]*d[2]))
333 else:
334 if component<0 or component>=len(self.data[0]):
335 error("Requested component",component,"does not fit the size of the data",len(self.data[0]))
336 for d in self.data:
337 data.append(d[component])
338 return data
339 else:
340 return self.data
341
342 - def __call__(self,
343 scaleX=1.,
344 scaleData=1,
345 offsetData=0,
346 offsetX=0):
347 """Return the data as SpreadsheetData-object"""
348
349 data=[]
350 if self.isVector():
351 for i,c in enumerate(self.col0):
352 data.append([scaleX*c+offsetX]+[scaleData*v+offsetData for v in self.data[i]])
353 else:
354 for i,c in enumerate(self.col0):
355 data.append([scaleX*c+offsetX,scaleData*self.data[i]+offsetData])
356
357 names=["col0"]
358 if self.isVector():
359 names+=[self.name+"_x",self.name+"_y",self.name+"_z"]
360 else:
361 names.append(self.name)
362
363 return SpreadsheetData(data=data,
364 names=names,
365 title="%s_t=%s" % (self.line(),self.time()))
366