1
2 """Collection of array of timelines"""
3
4 from PyFoam.Error import error
5 from math import ceil
6
8 """Mean value of a and b"""
9 return 0.5*(a+b)
10
12 """Absolute Maximum of a and b with the sign preserved"""
13 if a<0. or b<0.:
14 return min(a,b)
15 else:
16 return max(a,b)
17
19
20 possibleAccumulations=["first", "last", "min", "max", "average", "sum","count"]
21
22 - def __init__(self,
23 deflt=0.,
24 extendCopy=False,
25 splitThres=None,
26 splitFun=None,
27 advancedSplit=False,
28 accumulation="first"):
29 """@param deflt: default value for timelines if none has been defined before
30 @param extendCopy: Extends the timeline by cpying the last element
31 @param splitThres: Threshold after which the number of points is halved
32 @param splitFun: Function that is used for halving. If none is specified the mean function is used
33 @param advancedSplit: Use another split algorithm than one that condenses two values into one
34 @param accumulation: if more than one value is given at any time-step, how to accumulate them (possible values: "first", "last", "min", "max", "average", "sum","count")
35 """
36
37 self.cTime=None
38 self.times=[]
39 self.values={}
40 self.setDefault(deflt)
41 self.setExtend(extendCopy)
42 self.thres=None
43 self.fun=None
44
45 if not (accumulation in TimeLineCollection.possibleAccumulations):
46 error("Value",accumulation,"not in list of possible values:",TimeLineCollection.possibleAccumulations)
47 self.accumulation=accumulation
48 self.accumulations={}
49 self.occured={}
50
51 self.setSplitting(splitThres=splitThres,
52 splitFun=splitFun,
53 advancedSplit=advancedSplit)
54
62
63 - def setSplitting(self,splitThres=None,splitFun=None,advancedSplit=False):
64 """Sets the parameters for splitting"""
65 self.advancedSplit = advancedSplit
66 if self.advancedSplit:
67 self.splitLevels = []
68 if splitThres:
69 self.thres=splitThres
70 if (self.thres % 2)==1:
71 self.thres+=1
72
73 if splitFun:
74 self.fun=splitFun
75 elif not self.fun:
76 self.fun=mean
77
79 """@param deflt: default value to be used"""
80 self.defaultValue=float(deflt)
81
82 - def setExtend(self,mode):
83 """@param mode: whether or not to extend the timeline by copying or setting the default value"""
84 self.extendCopy=mode
85
87 """Number of elements in timelines"""
88 return len(self.times)
89
91 """Sets the time. If time is new all the timelines are extended
92 @param time: the new current time"""
93
94 dTime=float(time)
95
96 if dTime!=self.cTime:
97 self.cTime=dTime
98 self.times.append(self.cTime)
99 for v in self.values.values():
100 if len(v)>0 and self.extendCopy:
101 val=v[-1]
102 else:
103 val=self.defaultValue
104 v.append(val)
105 if self.thres:
106 if len(self.times)>=self.thres:
107 if self.advancedSplit:
108
109
110 if len(self.splitLevels)<len(self.times):
111 self.splitLevels+=[0]*(len(self.times)-len(self.splitLevels))
112 splitTill=int(len(self.times)*0.75)
113 if self.splitLevels[splitTill]!=0:
114
115 splitTill=self.splitLevels.index(0)
116 splitFrom=0
117 maxLevel=self.splitLevels[0]
118 for l in range(maxLevel):
119 li=self.splitLevels.index(l)
120 if li>=0 and li<splitTill/2:
121 splitFrom=li
122 break
123 window=4
124 if ((splitTill-splitFrom)/window)!=0:
125 splitTill=splitFrom+window*int(ceil((splitTill-splitFrom)/float(window)))
126
127
128 times=self.times[:splitFrom]
129 levels=self.splitLevels[:splitFrom]
130 values={}
131 for k in self.values:
132 values[k]=self.values[k][:splitFrom]
133
134 for start in range(splitFrom,splitTill,window):
135 end=start+window-1
136 sTime=self.times[start]
137 eTime=self.times[end]
138 times+=[sTime,(eTime-sTime)*(2./3)+sTime]
139 levels+=[self.splitLevels[start]+1,self.splitLevels[end]+1]
140 for k in self.values:
141 minV=self.values[k][start]
142 minI=0
143 maxV=self.values[k][start]
144 maxI=0
145 for j in range(1,window):
146 val=self.values[k][start+j]
147 if val>maxV:
148 maxV=val
149 maxI=j
150 if val<minV:
151 minV=val
152 minI=j
153 if minI<maxI:
154 values[k]+=[minV,maxV]
155 else:
156 values[k]+=[maxV,minV]
157 firstUnsplit=int(splitTill/window)*window
158 self.times=times+self.times[firstUnsplit:]
159 self.splitLevels=levels+self.splitLevels[firstUnsplit:]
160
161 for k in self.values:
162 self.values[k]=values[k]+self.values[k][firstUnsplit:]
163 assert len(self.times)==len(self.values[k])
164 else:
165 self.times=self.split(self.times,min)
166 for k in self.values.keys():
167 self.values[k]=self.split(self.values[k],self.fun)
168 self.occured={}
169
170 - def split(self,array,func):
171 """Makes the array smaller by joining every two points
172 @param array: the field to split
173 @param func: The function to use for joining two points"""
174
175 newLen=len(array)/2
176 newArray=[0.]*newLen
177
178 for i in range(newLen):
179 newArray[i]=func(array[2*i],array[2*i+1])
180
181 return newArray
182
184 """@return: A list of the time values"""
185 return self.times
186
188 """@return: A list with the names of the safed values"""
189 return self.values.keys()
190
192 """Gets a timeline
193 @param name: Name of the timeline
194 @return: List with the values"""
195
196 if not self.values.has_key(name):
197 self.values[name]=self.nr()*[self.defaultValue]
198 return self.values[name]
199
201 """Sets the value of the last element in a timeline
202 @param name: name of the timeline
203 @param value: the last element"""
204 data=self.getValues(name)
205 val=float(value)
206 if len(data)>0:
207 accu=self.accumulation
208 if not self.occured.has_key(name):
209 if accu=="count":
210 newValue=1L
211 else:
212 newValue=val
213 self.occured[name]=1
214 else:
215 oldValue=data[-1]
216 n=self.occured[name]
217 self.occured[name]+=1
218 if name in self.accumulations:
219 accu=self.accumulations[name]
220 if accu=="first":
221 newValue=oldValue
222 elif accu=="last":
223 newValue=val
224 elif accu=="max":
225 newValue=max(val,oldValue)
226 elif accu=="min":
227 newValue=min(val,oldValue)
228 elif accu=="sum":
229 newValue=val+oldValue
230 elif accu=="average":
231 newValue=(n*oldValue+val)/(n+1)
232 elif accu=="count":
233 newValue=n+1
234 else:
235 error("Unimplemented accumulator",accu,"for",name)
236
237 data[-1]=newValue
238