Package PyFoam :: Package RunDictionary :: Module SampleDirectory
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.RunDictionary.SampleDirectory

  1  #  ICE Revision: $Id:$ 
  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   
11 -class SampleDirectory(object):
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
42 - def __len__(self):
43 return len(self.times)
44
45 - def __iter__(self):
46 for t in self.times: 47 yield SampleTime(self.dir, 48 t, 49 prefixes=self.prefixes, 50 postfixes=self.postfixes)
51
52 - def __getitem__(self,time):
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
61 - def __contains__(self,time):
62 return time in self.times
63
64 - def sorttimes(self,x,y):
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
73 - def lines(self):
74 """Returns all the found sample lines""" 75 76 lines=[] 77 78 for t in self: 79 for l in t.lines: 80 if l not in lines: 81 lines.append(l) 82 lines.sort() 83 84 return lines
85
86 - def values(self):
87 """Returns all the found sampled values""" 88 89 values=[] 90 91 for t in self: 92 for v in t.values: 93 if v not in values: 94 values.append(v) 95 values.sort() 96 97 return values
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
130 -class SampleTime(object):
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
170 - def extractLine(self,fName):
171 """Extract the name of the line from a filename""" 172 return fName.split("_")[0]
173
174 - def extractValues(self,fName):
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
199 - def __getitem__(self,key):
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
248 - def determineIndex(self,fName,vName,data):
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
273 -class SampleData(object):
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
290 - def __repr__(self):
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
298 - def line(self):
299 """Get the line of the sample""" 300 return path.basename(self.file).split("_")[0]
301
302 - def time(self):
303 """Get the time of the sample (as a string)""" 304 return path.basename(path.dirname(self.file))
305
306 - def isVector(self):
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):
314 """Range of the data""" 315 data=self.component(component) 316 317 return (min(data),max(data))
318
319 - def domain(self):
320 """Range of the data domain""" 321 return (min(self.col0),max(self.col0))
322
323 - def component(self,component=None):
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