/[escript]/trunk/escript/py_src/timeseries.py
ViewVC logotype

Diff of /trunk/escript/py_src/timeseries.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/esys2/escript/py_src/timeseries.py revision 110 by jgs, Mon Feb 14 04:14:42 2005 UTC temp/escript/py_src/timeseries.py revision 1387 by trankine, Fri Jan 11 07:45:26 2008 UTC
# Line 1  Line 1 
1    #
2  # $Id$  # $Id$
3    #
4    #######################################################
5    #
6    #           Copyright 2003-2007 by ACceSS MNRF
7    #       Copyright 2007 by University of Queensland
8    #
9    #                http://esscc.uq.edu.au
10    #        Primary Business: Queensland, Australia
11    #  Licensed under the Open Software License version 3.0
12    #     http://www.opensource.org/licenses/osl-3.0.php
13    #
14    #######################################################
15    #
16    
17    """
18    Time serieas analysis
19    
20    @var __author__: name of author
21    @var __copyright__: copyrights
22    @var __license__: licence agreement
23    @var __url__: url entry point on documentation
24    @var __version__: version
25    @var __date__: date of the version
26    """
27    
28    
29    __author__="Lutz Gross, l.gross@uq.edu.au"
30    __copyright__="""  Copyright (c) 2006 by ACcESS MNRF
31                        http://www.access.edu.au
32                    Primary Business: Queensland, Australia"""
33    __license__="""Licensed under the Open Software License version 3.0
34                 http://www.opensource.org/licenses/osl-3.0.php"""
35    __url__="http://www.iservo.edu.au/esys/escript"
36    __version__="$Revision$"
37    __date__="$Date$"
38    
39    
40  import numarray  import numarray
41    from types import SliceType
42    DEFAULT_BUFFER_SIZE=1000
43    DEFAULT_FLOAT_TYPE=numarray.Float64
44    
45  class TimeSeriesBase:  class TimeSeriesBase:
46     """The TimeSeriesBase class is the base class for all class of the TimeSeries module.     """The TimeSeriesBase class is the base class for all class of the TimeSeries module."""
       It takes care of the updating depending TimeSeriesBase objects and the debuging mechnism"""  
47    
48     def __init__(self):     def __init__(self,debug=False,description="TimeSeriesBase"):
49         self.__debug=False         self.__debug=debug
50           self.setDescription(description)
51    
52     def __str__(self):     def __str__(self):
53         return "TimeSeriesBase"         return self.__description
54      
55       def setDescription(self,text):
56           self.__description=text
57    
58     def setDebugOn(self):     def setDebugOn(self):
59        """switch on degugging mode"""        """switch on degugging mode"""
# Line 30  class TimeSeriesBase: Line 73  class TimeSeriesBase:
73     def debug(self):     def debug(self):
74        """returns true if debug mode is on"""        """returns true if debug mode is on"""
75        return self.__debug        return self.__debug
         
 class TimeSeriesFilter(TimeSeriesBase):  
    """TimeSeriesFilter objects are applied to TimeSeries objects to filer out information or to convert it.  
       A TimeSeriesFilter objects is called by the TimeSeries object it is depending on to consider the values currently in the buffer for  
       updating. Some TimeSeriesFilter may require values outside the buffer. The TimeSeries object maintains the last buffer_overlap values  
       in the buffer so they can be used to process (not neccesarily all) value in the buffer."""  
76    
77     def __init__(self,buffer_overlap=0):  #============================================================================================================
78         self.__left_required_extension=buffer_overlap  class TimeSeriesBaseDataset(TimeSeriesBase):
79       """provides an interface for accessing a set of linearly ordered data."""
80     def __str__(self):     def __init__(self,buffer,offset=0,debug=False,description="TimeSeriesDataset"):
81         return "TimeSeriesFilter"         TimeSeriesBase.__init__(self,debug,description)
82           self.__buffer=buffer
83           self.__offset=offset
84           if self.debug(): print "Debug: %s: offset %d to buffer"%(self,self.getOffset())
85    
86       def __len__(self):
87           """needed to handle negative indexing in slicing"""
88           return 0
89    
90     def getBufferOverlapNeededForUpdate(self):     def getNumComponents(self):
91         return self.__left_required_extension         """returns the number of components of the data (may be overwritten by subclass)"""
92           return self.getBaseBuffer().getNumComponents()
93    
94     def update(self,times,values):     def getIdOfLastDatum(self):
95         pass        """returns the identification number of the last datum in the data set (may be overwritten by subclass)"""
96          return self.getBaseBuffer().getIdOfLastDatum()-self.getOffset()
97    
98       def getIdOfFirstDatum(self):
99          """returns the identification number of the first datum (may be overwritten by subclass)"""
100          return self.getBaseBuffer().getIdOfFirstDatum()-self.getOffset()
101    
102       def getIdOfFirstAvailableDatum(self):
103          """returns the identification number of the first avaiable datum (may be overwritten by subclass)"""
104          return self.getBaseBuffer().getIdOfFirstAvailableDatum()-self.getOffset()
105    
106       def getOffsetInBaseBuffer(self):
107          """returns the offset to access elements in getBaseBuffer() (may be overwritten by subclass)"""
108          return  self.getOffset()
109    
110       def getIdOfLastUnreferencedDatum(self):
111           """returns the identification number of the last datum which has been unused by all TimeSeries refering to the TimeSeriesBaseDataset (may be overwritten by subclass)"""
112           return self.getBaseBuffer().getIdOfLastUnreferencedDatum()-self.getOffset()
113    
114       def updateIdOfLastUnreferencedDatum(self,last_unreferenced_datum):
115           """updates the identification number of the last unused datum (to be overwritten by subclass)"""
116           self.getBaseBuffer().updateIdOfLastUnreferencedDatum(last_unreferenced_datum+self.getOffset())
117    
118       def append(self,values):
119           """appends data to the buffer. If the buffer would be full the buffer is rearranged before the data are appended  (to be overwritten by subclass)"""
120           self.getBaseBuffer().append(values)
121    
122       def getBaseBufferSize(self):
123           """returns the size of the buffer (to be overwritten by subclass)"""
124           return self.getBaseBuffer().getBaseBufferSize()
125      
126       def needsRearrangement(self,num_new_data=0):
127           """returns True if the buffer will be full after num_new_data have been appended (to be overwritten by subclass)"""
128           return self.getBaseBuffer().needsRearrangement(num_new_data)
129    
130       def isEmpty(self):
131          """returns true if no data are appeneded to buffer"""
132          return self.getNumData()<=0
133      
134       def getNumData(self):
135          """returns the number of data (not all of them are accessible)"""
136          return self.getIdOfLastDatum()-self.getIdOfFirstDatum()+1
137    
138       def getBaseBuffer(self):
139          """return the buffer referenced by the TimeSeriesBaseDataset"""
140          return self.__buffer
141    
142       def getOffset(self):
143          """return the offset when referring to dataset elements"""
144          return self.__offset
145    
146       def __getitem__(self,index):
147          """returns the datum index"""
148          if type(index)==SliceType:
149             start=index.start
150             end=index.stop
151             if start==end:
152                return self[start]
153             else:
154                 if start<self.getIdOfFirstDatum() or start>self.getIdOfLastDatum() or \
155                     end-1<self.getIdOfFirstDatum() or end-1>self.getIdOfLastDatum(): raise IndexError,"%s: Index [%d:%d] out of range"%(self,start,end)
156                 return self.getBaseBuffer()[start+self.getOffsetInBaseBuffer():end+self.getOffsetInBaseBuffer()]
157          else:
158             if index<self.getIdOfFirstDatum() or index>self.getIdOfLastDatum(): raise IndexError,"%s: Index %d out of range"%(self,index)
159             return self.getBaseBuffer()[index+self.getOffsetInBaseBuffer()]
160    
161  _DEFAULT_CACHE_SIZE=9  class TimeSeriesBaseBuffer(TimeSeriesBaseDataset):
162  _DEFAULT_BUFFER_SIZE=5     """An inplementation of TimeSeriesBaseDataset which actually is storing data into a numarray buffer"""
163  _FLOATING_TYPE=numarray.Float64     def __init__(self,buffer_size=DEFAULT_BUFFER_SIZE,numComponents=1,type=DEFAULT_FLOAT_TYPE,id_of_first_datum=0,debug=False,description="TimeSeriesBaseBuffer"):
   
 class TimeSeries(TimeSeriesBase):  
    def __init__(self,buffer_overlap=0,buffer_size=_DEFAULT_BUFFER_SIZE,cache_size=_DEFAULT_CACHE_SIZE,numComponents=1):  
        if buffer_size>cache_size: raise ValueError,"buffer size has to be less or equal cache size"  
        TimeSeriesBase.__init__(self)  
        self.__updates=list()  
        self.__max_buffer_overlap=0  
        self.__buffer_overlap=0  
        self.__numNodes=0  
        self.__numNodesInBuffer=0  
        self.__numNodesInCache=0  
        self.__firstNodeInBuffer=0  
        self.__firstNodeInCache=0  
        self.__buffer_size=buffer_size  
        self.__node_cache=numarray.zeros((cache_size,),_FLOATING_TYPE)  
        self.__attachment_cache=[]  
164         if numComponents<2:         if numComponents<2:
165            self.__value_cache=numarray.zeros((cache_size,),_FLOATING_TYPE)            buffer=numarray.zeros((buffer_size,),type)
166         else:         else:
167            self.__value_cache=numarray.zeros((cache_size,numComponents),_FLOATING_TYPE)            buffer=numarray.zeros((buffer_size,numComponents),type)
168         self.resizeMaxBufferOverlap(buffer_overlap)         TimeSeriesBaseDataset.__init__(self,buffer,id_of_first_datum-1,debug,description)
169           self.__num_data_in_buffer=0
170     def __del__(self):         self.__id_last_unreferenced_datum=id_of_first_datum-1
171         self.flush()         self.__id_last_datum=id_of_first_datum-1
172           self.__id_first_datum=id_of_first_datum
173           if self.debug(): print "Debug: %s : buffer of size %d with %d components allocated (first datum is %d)."% \
174                           (self,self.getBaseBufferSize(),self.getNumComponents(),id_of_first_datum)
175    
    def __str__(self):  
        return "TimeSeries"  
176    
177       def getBaseBufferSize(self):
178           """returns the size of the buffer"""
179           return self.getBaseBuffer().shape[0]
180      
181     def getNumComponents(self):     def getNumComponents(self):
182         if self.__value_cache.rank==1:         """returns the number of components of the data (overwrites TimeSeriesBaseDataset method)"""
183           if self.getBaseBuffer().rank==1:
184            return 1            return 1
185         else:         else:
186            self.__value_cache.shape[1]            self.getBaseBuffer().shape[1]
187    
188     def getNumNodes(self):     def getNumDataInBaseBuffer(self):
189         """returns the number of time nodes in the time series"""         """returns the number of data currently in the buffer"""
190         return self.__numNodes         return self.__num_data_in_buffer
191    
192     def getCacheSize(self):     def getIdOfLastDatum(self):
193         """returns the cache size"""        """returns the identification number of the last datum in the data set (overwrites method from TimeSeriesBaseDataset)"""
194         return self.__node_cache.shape[0]        return self.__id_last_datum
195    
196     def getBufferSize(self):     def getIdOfFirstDatum(self):
197         """returns the cache size"""        """returns the identification number of the first datum (overwrites method from TimeSeriesBaseDataset)"""
198         return self.__buffer_size        return self.__id_first_datum
199    
200     def getNumNodesInCache(self):     def getOffsetInBaseBuffer(self):
201         """returns the number of nodes in cache"""        """returns the offset to access elements in the buffer (overwrites method from TimeSeriesBaseDataset)"""  
202         return self.__numNodesInCache        return -self.getIdOfLastDatum()+self.getNumDataInBaseBuffer()-1  
203    
204     def getNumNodesInBuffer(self):     def getIdOfLastUnreferencedDatum(self):
205         """returns the number of nodes in cache"""         """returns the identification number of the last datum which has been unused by all TimeSeries refering to the TimeSeriesBaseDataset (overwrites method from TimeSeriesBaseDataset)"""
206         return self.__numNodesInBuffer         return self.__id_last_unreferenced_datum
207        
208     def getFirstNodeInCache(self):     def updateIdOfLastUnreferencedDatum(self,last_unreferenced_datum):
209         """returns the id number of the first node in the cache"""         """updates the identification number of the last unused datum (to be overwritten by subclass)"""
210         return self.__firstNodeInCache         self.getBaseBuffer().updateIdOfLastUnreferencedDatum(last_unreferenced_datum-self.getOffset())
211    
212     def getFirstNodeInBuffer(self):     def updateIdOfLastUnreferencedDatum(self,last_unreferenced_datum):
213         """returns the id number of the first node in the buffer"""         """updates the identification number of the last unused datum (overwrites TimeSeriesBaseDataset method)"""
214         return self.__firstNodeInBuffer         if self.__id_last_unreferenced_datum>last_unreferenced_datum:
215               self.__id_last_unreferenced_datum=last_unreferenced_datum
216     def getFirstNodeOfBufferInCache(self):             if self.debug(): print "Debug: %s: last unused datum is now %s"%(self,last_unreferenced_datum)
217         """returns the first location of the first node in the buffer relative to the cache"""  
218         return self.getFirstNodeInBuffer()-self.getFirstNodeInCache()     def needsRearrangement(self,num_new_data=0):
219           """returns True if the buffer will be full after num_new_data have been appended"""
220     def getBufferOverlap(self):         return self.getNumDataInBaseBuffer()+num_new_data>self.getBaseBufferSize()
221         """returns the current size of the left extension"""          
222         return self.__buffer_overlap     def getIdOfFirstAvailableDatum(self):
223          """returns the identification number of the first avaiable datum (overwrites TimeSeriesBaseDataset method)"""
224     def getMaxBufferOverlap(self):        return self.getIdOfLastDatum()-self.__num_data_in_buffer+1
225         """returns the maximum size of the left extension"""  
226         return self.__max_buffer_overlap     def append(self,data):
227          """appends data to the buffer. If the buffer would be full the buffer is rearranged before the data are appended (overwrites TimeSeriesBaseDataset method)"""
228     def resizeMaxBufferOverlap(self,new_buffer_overlap=0):        data=numarray.array(data)
229         if new_buffer_overlap>self.__max_buffer_overlap:        nc=self.getNumComponents()
230            if self.getNumNodes()>0: raise ValueError,"left extension can only be resized for empty time series"        if data.rank==0:
231            if self.getCacheSize()<self.getBufferSize()+new_buffer_overlap:          if nc==1:
232                 raise ValueError,"Cache size is too small! required cache size is %s"%self.getBufferSize()+new_buffer_overlap             num_new_data=1
233            self.__max_buffer_overlap=new_buffer_overlap          else:
234            if self.debug(): print "Debug: %s: left extension is increased to %d"%(self,new_buffer_overlap)             raise ValueError,"%s: illegal data shape"%self
235          elif data.rank==1:
236     def getLastNode(self):          if nc==1:
237         if self.getNumNodesInCache()>0:               num_new_data=data.shape[0]
238            return self.__node_cache[self.getNumNodesInCache()-1]          else:
239         else:               num_new_data=1  
240            return -1.e300        elif data.rank==2:
241            if not nc==data.shape[1]: raise ValueError,"%s: illegal data shape"%self
242     def getLastValue(self):          num_new_data=data.shape[0]
243         if self.getNumNodesInCache()>0:        else:
244            return self.__node_cache[self.getNumNodesInCache()-1]           raise ValueError,"%s: illegal rank"%self
        else:  
           raise ValueError,"No value available"  
245    
246     def checkInUpdate(self,time_series_filter):        # check is buffer will be overflown when data are appended:
247         """checks in a time_series_filter object to be updated when buffer is full"""        if self.needsRearrangement(num_new_data):
248         if self.getNumNodes()>0:          nn=self.getNumDataInBaseBuffer()
249            raise TypeError,"Check in of TimeSeries requires empty buffer."          num_protected_data=self.getIdOfLastDatum()-self.getIdOfLastUnreferencedDatum()
250         self.__updates.append(time_series_filter)          if num_protected_data+num_new_data>self.getBaseBufferSize():
251         self.resizeMaxBufferOverlap(time_series_filter.getBufferOverlapNeededForUpdate())                raise ValueError,"%s: buffer overflow: buffer size has to be bigger than %d"%(self,num_protected_data+num_new_data)
252         if self.debug(): print "Debug: %s: %s checked in successfully."%(self,time_series_filter)          if num_protected_data>0: self.getBaseBuffer()[0:num_protected_data]=self.getBaseBuffer()[nn-num_protected_data:nn]
253            self.__num_data_in_buffer=num_protected_data
254     def append(self,time_nodes,values,attachments=None):          self.__id_last_unreferenced_datum=self.__id_last_datum
255         """appends the time_nodes and values into the buffer"""          if self.debug():
256         num_additional_nodes=time_nodes.shape[0]               print "Debug: %s: rearrangement: first data in buffer is %d."%(self,self.getIdOfLastDatum()-self.getNumDataInBaseBuffer()+1)
257         if num_additional_nodes<1: return        # copy data over:
258         if self.debug():        nn=self.getNumDataInBaseBuffer()
259              if num_additional_nodes>1:        self.getBaseBuffer()[nn:nn+num_new_data]=data
260                 print "Debug: %s: values %d to %d are added to time series."%(self,self.getNumNodes(),self.getNumNodes()+num_additional_nodes-1)        self.__num_data_in_buffer+=num_new_data
261              else:        self.__id_last_datum+=num_new_data
262                 print "Debug: %s: value %d is added to time series."%(self,self.getNumNodes())        self.__id_last_unreferenced_datum+=num_new_data
263         if not num_additional_nodes==values.shape[0]:        if self.debug(): print "Debug: %s: %d data appended. Last unreferenced datum is now %d."%(self,num_new_data,self.__id_last_unreferenced_datum)
264            raise ValueError,"Number time nodes and number of values don't match."  
265         if self.getLastNode()>=time_nodes[0]:  # ======================================
266            raise ValueError,"first time node to be checked in is less than last previously checked in node"  class TimeSeriesControlerView(TimeSeriesBase):
267          """A TimeSeriesControlerView is attached to a Controler and moves forward in time by increasing the id of the last processed datum.
268         if num_additional_nodes>1:           Any implementation of a TimeSeriesControlerView must provide the getControler method which returns the controler"""
269              if min(time_nodes[1:num_additional_nodes]-time_nodes[0:num_additional_nodes-1])<=0:        def __init__(self,id_first_datum=0,debug=False,description="TimeSeries"):
270                raise ValueError,"time nodes have to be strictly increasing"          TimeSeriesBase.__init__(self,debug,description)
271            self.__id_last_processed_datum=id_first_datum-1
272            if self.debug(): print "Debug: %s  created with first datum %d"%(str(self),id_first_datum)
273    
274          def getIdOfLastProcessedDatum(self):
275              return self.__id_last_processed_datum
276    
277          def updateIdOfLastProcessedDatum(self,id_last_processed_datum):
278              self.__id_last_processed_datum=id_last_processed_datum
279    
280          # def getControler(self):
281          #      """returns the Controler of the time series (to be overwritten by subclass)"""
282          #      pass
283    
284    class TimeSeries(TimeSeriesBaseDataset,TimeSeriesControlerView):
285          """makes TimeSeriesBaseDataset look like a TimeSeries and introduces operations
286             Any implementation of a TimeSeriesControlerView must provide the getControler method which returns the controler"""
287          def __init__(self,dataset,debug=False,description="TimeSeries"):
288            TimeSeriesControlerView.__init__(self,dataset.getIdOfFirstDatum(),debug,description)
289            TimeSeriesBaseDataset.__init__(self,dataset,0,debug,description)
290                
291         # full cache requires a shift:        def getDataset(self):
292         if self.getNumNodesInCache()+num_additional_nodes>self.getCacheSize():            """returns the TimeSeriesBaseDataset of the time series"""
293             new_num_nodes_in_cache=self.getNumNodesInBuffer()+self.getBufferOverlap()            return self.getBaseBuffer()
294             if new_num_nodes_in_cache+num_additional_nodes>self.getCacheSize():  
295                raise ValueError,"Cache overflow: Expected size is bigger than %d"%(new_num_nodes_in_cache+num_additional_nodes)        # def getControler(self):
296             start=self.getNumNodesInCache()-new_num_nodes_in_cache        #      """returns the Controler of the time series (to be overwritten by subclass)"""
297             end=start+new_num_nodes_in_cache        #      pass
298             self.__node_cache[0:new_num_nodes_in_cache]=self.__node_cache[start:end]  
299             self.__value_cache[0:new_num_nodes_in_cache]=self.__value_cache[start:end]        def __add__(self,arg):
300             self.__attachment_cache[0:new_num_nodes_in_cache]=self.__attachment_cache[start:end]           if isinstance(arg,TimeSeriesBaseDataset):
301                return TimeSeriesAdd(self,arg)
302             self.__firstNodeInCache+=start           else:
303             self.__numNodesInCache=new_num_nodes_in_cache              return TimeSeriesAddScalar(self,arg)
304             if self.debug(): print "Debug: %s: %d values from %d onwards are moved to the beginning of the cache (first node in cache is now %d)."% \  
305                                                                                      (self,new_num_nodes_in_cache,start,self.__firstNodeInCache)        def __sub__(self,arg):
306                       return self+(-1.)*arg
307         # copy values into cache:  
308         if self.getNumNodesInCache()+num_additional_nodes>self.getCacheSize():        def __mul__(self,arg):
309             raise ValueError,"Cache overflow: Expected size is bigger than %d"%(self.getNumNodesInCache()+num_additional_nodes)           if isinstance(arg,TimeSeriesBaseDataset):
310         if self.debug():              return TimeSeriesMult(self,arg)
311             if num_additional_nodes>1:           else:
312                print "Debug: %s: values %d to %d of cache are updated"%(self,self.getNumNodesInCache(),self.getNumNodesInCache()+num_additional_nodes-1)              return TimeSeriesMultScalar(self,arg)
313             else:  
314                print "Debug: %s: value %d of cache is updated."%(self,self.getNumNodesInCache())        def __div__(self,arg):
315         self.__node_cache[self.getNumNodesInCache():self.getNumNodesInCache()+num_additional_nodes]=time_nodes           if isinstance(arg,TimeSeriesBaseDataset):
316         self.__value_cache[self.getNumNodesInCache():self.getNumNodesInCache()+num_additional_nodes]=values              return TimeSeriesDiv(self,arg)
317         self.__numNodes+=num_additional_nodes           else:
318         self.__numNodesInBuffer+=num_additional_nodes              return TimeSeriesMultScalar(self,1./arg)
319         self.__numNodesInCache+=num_additional_nodes  
320         print self.__node_cache        def __pow__(self,arg):
321         print self.__value_cache           if isinstance(arg,TimeSeriesBaseDataset):
322         # copy values into cache:              return TimeSeriesPower(self,arg)
323         if self.getNumNodesInBuffer()>=self.getBufferSize():           else:
324                if self.debug() and len(self.__updates)>0: print "Debug: %s: buffer is full. Updating process is started"%self              return TimeSeriesPowerScalar(self,arg)
325                self.processBuffer()        
326          def __radd__(self,arg):
327             return self.__add__(arg)
328    
329     def flush(self):        def __rsub__(self,arg):
330        self.processBuffer()           return arg+(-1.)*self
331    
332          def __rmul__(self,arg):
333             return self.__mul__(arg)
334    
335     def processBuffer(self):        def __rdiv__(self,arg):
336          if self.getNumNodesInBuffer()>0:           if isinstance(arg,TimeSeriesBaseDataset):
337             for i in self.__updates:              return TimeSeriesDiv(arg,self)
338               if self.debug(): print "Debug: %s: update for %s started"%(self,i)           else:
339               if i.getBufferOverlapNeededForUpdate()>self.getBufferOverlap():              return TimeSeriesDivScalar(self,arg)
340                  s=self.getFirstNodeOfBufferInCache()  
341                  l=self.getNumNodesInBuffer()        def __rpow__(self,arg):
342             if isinstance(arg,TimeSeriesBaseDataset):
343                return TimeSeriesPower(arg,self)
344             else:
345                return Exp(numarray.log(arg)*self)
346    
347          def __lshift__(self,arg):
348             return TimeSeriesShift(self,-arg)
349    
350          def __rshift__(self,arg):
351             return TimeSeriesShift(self,arg)
352    
353          def __neg__(self):
354             return (-1.0)*self
355    
356          def __pos__(self):
357             return (1.0)*self
358    
359    class TimeSeriesOperator(TimeSeriesControlerView):
360          """a TimeSeriesOperator decribes an operation acting on list of TimeSeries time_series_args. It allows to update its output (if there is any)
361             through the update method which is overwritten by a particular implementation of the class. The update method is called to process the data [start:end] using
362             [start-left_wing_size:end+right_wing_size] of its arguments"""
363          def __init__(self,controler,time_series_args=[],left_wing_size=0,right_wing_size=0,debug=False,description="TimeSeriesOperator"):
364              id_first_datum=controler.getIdOfFirstDatum()
365              for i in time_series_args: id_first_datum=max(id_first_datum,i.getIdOfFirstDatum())
366              TimeSeriesControlerView.__init__(self,id_first_datum+left_wing_size,debug,description)
367              self.__left_wing_size=left_wing_size
368              self.__right_wing_size=right_wing_size
369              self.__time_series_args=time_series_args
370              self.__controler=controler
371              controler.appendOperatorToUpdateList(self)
372              if self.debug(): print "Debug: %s: with left/right wing size %d/%d and %d arguments."%(str(self),left_wing_size,right_wing_size,len(time_series_args))
373    
374          def __del__(self):
375              self.getControler().removeOperatorFromUpdateList(self)
376    
377          def getControler(self):
378              """returns the Controler updating the TimeSeriesOperator"""
379              return self.__controler
380    
381          def getLeftWingSize(self):
382              """returns the left wing size"""  
383              return self.__left_wing_size
384    
385          def getRightWingSize(self):
386              """returns the right wing size"""
387              return self.__right_wing_size
388    
389          def getArguments(self,index=None):
390              """returns the list of arguments or, index is present, the argument with index index. In the latter case None is returned if no arguments are present"""
391              if index==None:
392                 return self.__time_series_args
393              else:
394                 if len(self.__time_series_args)>0:
395                    return self.__time_series_args[index]
396               else:               else:
397                  s=self.getFirstNodeOfBufferInCache()-i.getBufferOverlapNeededForUpdate()                  return None
                 l=self.getNumNodesInBuffer()+i.getBufferOverlapNeededForUpdate()  
              i.update(self.__node_cache[s:s+l],self.__value_cache[s:s+l])  
            self.__firstNodeInBuffer+=self.__numNodesInBuffer  
            self.__numNodesInBuffer=0  
         self.__buffer_overlap=self.getMaxBufferOverlap()  
         if self.debug(): print "Debug: %s: first node in buffer is now %d"%(self,self.__firstNodeInBuffer)  
398    
399            def getArgumentDataset(self,index):
400              """returns the dataset of in the argument with index index"""
401              arg=self.getArguments(index)
402              if arg==None:
403                 return None
404              else:
405                  return self.getArguments(index).getDataset()
406    
407          def flush(self):
408              """calls the update method with all the maximum processable range. It also updates the id of unused datum for all arguments"""
409              start=self.getIdOfLastProcessedDatum()+1
410              end=self.getControler().getIdOfLastDatum()
411              for i in self.getArguments(): end=min(end,i.getIdOfLastDatum())
412              if start<=end-self.getRightWingSize():
413                 if self.debug(): print "Debug: %s: range [%d:%d] is updated."%(self,start,end-self.getRightWingSize())
414                 self.update(start,end-self.getRightWingSize()+1)      
415                 for i in self.getArguments(): i.updateIdOfLastUnreferencedDatum(end-self.getLeftWingSize())
416                 self.updateIdOfLastProcessedDatum(end)
417    
418          def update(self,start,end):
419              """updates the the data [start:end] using [start-left_wing_size:end+right_wing_size] of its arguments (is overwritten by a particular TimeSeriesOperator)"""
420              pass
421    
422    
423    class TimeSeriesFilter(TimeSeries,TimeSeriesOperator):
424          """a TimeSeriesFilter is a TimeSeries taht is created trough a TimeSeriesOperator"""
425          def __init__(self,controler,dataset,time_series_args=[],left_wing_size=0,right_wing_size=0,debug=False,description="TimeSeriesFilter"):
426             TimeSeriesOperator.__init__(self,controler,time_series_args,left_wing_size,right_wing_size,debug,description)
427             TimeSeries.__init__(self,dataset,debug,description)
428    
429          def update(self,start,end):
430              """appends zeros to the dataset. This method should be overwritten by a particular TimeSeriesFilter"""
431              nc=self.getNumComponents()
432              if nc>1:
433                 self.getDataset().append(numarray.zeros([nc,end-start]))
434              else:
435                 self.getDataset().append(numarray.zeros(end-start))
436    
437    class Controler(TimeSeries):
438       """controls a set of TimeSeries"""
439       def __init__(self,buffer_size=DEFAULT_BUFFER_SIZE,debug=False,description="TimeSeriesControler"):
440            TimeSeries.__init__(self,TimeSeriesBaseBuffer(buffer_size,1,DEFAULT_FLOAT_TYPE,0,debug,"node buffer of "+description),debug,"nodes of "+description)
441            self.setFlushRate()  
442            self.__update_time_series=list()
443          
444       def getControler(self):
445           """returns the Controler of the time series (overwrites method of by TimeSeries)"""
446           return self
447    
448       def setFlushRate(self,rate=50):
449           """set the flush rate, i.e. after rate new time nodes have been checked in the flush method is called."""
450           self.__flush_rate=rate
451           if self.debug(): print "Debug: %s: flush rate is set to %d"%(self,rate)
452    
453       def needsFlushing(self):
454          """returns true if the depending TimeSeriesFilters needs to be flushed becuase the time nodes buffer is full or because of the set flush rate"""
455          return self.needsRearrangement(1) or (self.getNumData()+1)%self.__flush_rate==0
456    
457       def flush(self):
458           """flushes all dependend TimeSeriesFilters by processing their flush method"""
459           if self.debug(): print "Debug: %s: start flushing"%self
460           for time_serie in self.__update_time_series: time_serie.flush()
461    
462       def appendOperatorToUpdateList(self,time_serie):
463           if not time_serie.getControler()==self: raise ValueError,"%s: TimeSeries %s is not defined on this controler."%(self,time_serie)
464           if not self.isEmpty(): raise ValueError,"%s: you can only check in a time series time_serie is controler is empty."%self
465           self.__update_time_series.append(time_serie)
466           if self.debug(): print "Debug: %s: %s has been added to update list."%(self,time_serie)
467    
468       def removeOperatorFromUpdateList(self,time_serie):
469           self.__update_time_series.remove(time_serie)
470           if self.debug(): print "Debug: %s: %s has been removed from update list."%(self,time_serie)
471    
472       def nextTime(self,value):
473           if self.needsFlushing(): self.flush()
474           self.getDataset().append(value)
475           if self.debug(): print "Debug: %s: new time node %e has been added."%(self,value)
476    
477    class TimeSeriesShift(TimeSeries):
478          """creates a shift of the time series, i.e. if d[n] is the datum at time t[n], the value at t[n] becomes v[n+shift] on the output"""
479          def __init__(self,time_serie,shift=1):
480              if shift<0:
481                  dsc="(%s)<<%d"%(time_serie,-shift)
482              else:
483                  dsc="(%s)>>%d"%(time_serie,shift)
484              self.__controler=time_serie.getControler()
485              TimeSeries.__init__(self,TimeSeriesBaseDataset(time_serie.getDataset(),-shift,time_serie.debug(),"buffer view to "+dsc),time_serie.debug(),dsc)
486    
487          def getControler(self):
488              return self.__controler
489    
490    class TimeSeriesAdd(TimeSeriesFilter):
491          """adds two TimeSeries"""
492          def __init__(self,time_serie_1,time_serie_2):
493              dsc="(%s)+(%s)"%(time_serie_1,time_serie_2)
494              dbg=time_serie_1.debug() or time_serie_2.debug()
495              cntrl=time_serie_1.getControler()
496              if not cntrl==time_serie_2.getControler():
497                      raise ValueError("TimeSeriesAdd: %s and %s have different controler."%(time_serie_1,time_serie_2))
498              id_first_datum=max(time_serie_1.getIdOfFirstDatum(),time_serie_2.getIdOfFirstDatum())
499              TimeSeriesFilter.__init__(self,cntrl, \
500                                  TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie_1.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
501                                  [time_serie_1,time_serie_2],0,0,dbg,dsc)
502    
503          def update(self,start,end):
504              self.append(self.getArgumentDataset(0)[start:end]+self.getArgumentDataset(1)[start:end])
505    
506    class TimeSeriesAddScalar(TimeSeriesFilter):
507          """adds a single value to a TimeSeries"""
508          def __init__(self,time_serie,scalar):
509              dsc="(%s)+(%s)"%(time_serie,scalar)
510              dbg=time_serie.debug()
511              cntrl=time_serie.getControler()
512              id_first_datum=time_serie.getIdOfFirstDatum()
513              TimeSeriesFilter.__init__(self,cntrl, \
514                           TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
515                           [time_serie],0,0,dbg,dsc)
516              self.__scalar=scalar
517    
518          def update(self,start,end):
519              self.append(self.getArgumentDataset(0)[start:end]+self.__scalar)
520    
521    class TimeSeriesMult(TimeSeriesFilter):
522          """multiplies two TimeSeries"""
523          def __init__(self,time_serie_1,time_serie_2):
524              dsc="(%s)*(%s)"%(time_serie_1,time_serie_2)
525              dbg=time_serie_1.debug() or time_serie_2.debug()
526              cntrl=time_serie_1.getControler()
527              if not cntrl==time_serie_2.getControler():
528                      raise ValueError("TimeSeriesMult: %s and %s have different controler."%(time_serie_1,time_serie_2))
529              id_first_datum=max(time_serie_1.getIdOfFirstDatum(),time_serie_2.getIdOfFirstDatum())
530              TimeSeriesFilter.__init__(self,cntrl, \
531                       TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie_1.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
532                       [time_serie_1,time_serie_2],0,0,dbg,dsc)
533    
534          def update(self,start,end):
535              self.append(self.getArgumentDataset(0)[start:end]*self.getArgumentDataset(1)[start:end])
536    
537    class TimeSeriesMultScalar(TimeSeriesFilter):
538          """multiplies a TimeSeries with a single value"""
539          def __init__(self,time_serie,scalar):
540              dsc="(%s)*%s"%(time_serie,scalar)
541              dbg=time_serie.debug()
542              cntrl=time_serie.getControler()
543              id_first_datum=time_serie.getIdOfFirstDatum()
544              TimeSeriesFilter.__init__(self,cntrl, \
545                           TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
546                           [time_serie],0,0,dbg,dsc)
547              self.__scalar=scalar
548    
549          def update(self,start,end):
550              self.append(self.getArgumentDataset(0)[start:end]*self.__scalar)
551    
552    class TimeSeriesDiv(TimeSeriesFilter):
553          """divides two TimeSeries"""
554          def __init__(self,time_serie_1,time_serie_2):
555              dsc="(%s)/(%s)"%(time_serie_1,time_serie_2)
556              dbg=time_serie_1.debug() or time_serie_2.debug()
557              cntrl=time_serie_1.getControler()
558              if not cntrl==time_serie_2.getControler():
559                      raise ValueError("TimeSeriesDiv: %s and %s have different controler."%(time_serie_1,time_serie_2))
560              id_first_datum=max(time_serie_1.getIdOfFirstDatum(),time_serie_2.getIdOfFirstDatum())
561              TimeSeriesFilter.__init__(self,cntrl, \
562                         TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie_1.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
563                         [time_serie_1,time_serie_2],0,0,dbg,dsc)
564    
565          def update(self,start,end):
566              self.append(self.getArgumentDataset(0)[start:end]/self.getArgumentDataset(1)[start:end])
567    
568    class TimeSeriesDivScalar(TimeSeriesFilter):
569          """divides a scalar be a TimeSerie"""
570          def __init__(self,time_serie,scalar):
571              dsc="(%s)/(%s)"%(scalar,time_serie)
572              dbg=time_serie.debug()
573              cntrl=time_serie.getControler()
574              id_first_datum=time_serie.getIdOfFirstDatum()
575              TimeSeriesFilter.__init__(self,cntrl, \
576                           TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
577                           [time_serie],0,0,dbg,dsc)
578              self.__scalar=scalar
579    
580          def update(self,start,end):
581              self.append(self.__scalar/self.getArgumentDataset(0)[start:end])
582    
583    class TimeSeriesPower(TimeSeriesFilter):
584          """raise one TimeSeries to the power of an other TimeSeries"""
585          def __init__(self,time_serie_1,time_serie_2):
586              dsc="(%s)**(%s)"%(time_serie_1,time_serie_2)
587              dbg=time_serie_1.debug() or time_serie_2.debug()
588              cntrl=time_serie_1.getControler()
589              if not cntrl==time_serie_2.getControler():
590                      raise ValueError("TimeSeriesPower: %s and %s have different controler."%(time_serie_1,time_serie_2))
591              id_first_datum=max(time_serie_1.getIdOfFirstDatum(),time_serie_2.getIdOfFirstDatum())
592              TimeSeriesFilter.__init__(self,cntrl, \
593                    TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie_1.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
594                    [time_serie_1,time_serie_2],0,0,dbg,dsc)
595    
596          def update(self,start,end):
597              self.append(self.getArgumentDataset(0)[start:end]**self.getArgumentDataset(1)[start:end])
598    
599    class TimeSeriesPowerScalar(TimeSeriesFilter):
600          """raises a TimeSerie to the power of a scalar"""
601          def __init__(self,time_serie,scalar):
602              dsc="(%s)**(%s)"%(time_serie,scalar)
603              dbg=time_serie.debug()
604              cntrl=time_serie.getControler()
605              id_first_datum=time_serie.getIdOfFirstDatum()
606              TimeSeriesFilter.__init__(self,cntrl, \
607                           TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
608                           [time_serie],0,0,dbg,dsc)
609              self.__scalar=scalar
610    
611          def update(self,start,end):
612              self.append(self.getArgumentDataset(0)[start:end]**self.__scalar)
613    
614    class Exp(TimeSeriesFilter):
615          """"""
616          def __init__(self,time_serie):
617              dsc="exp(%s)"%(time_serie)
618              dbg=time_serie.debug()
619              cntrl=time_serie.getControler()
620              id_first_datum=time_serie.getIdOfFirstDatum()
621              TimeSeriesFilter.__init__(self,cntrl, \
622                         TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
623                         [time_serie],0,0,dbg,dsc)
624    
625          def update(self,start,end):
626              self.append(numarray.exp(self.getArgumentDataset(0)[start:end]))
627    
628    class Writer(TimeSeriesOperator):
629          """writes the time series into an output strim ostream which mast have the writeline method. The values are seperated by the string seperator."""
630          def __init__(self,time_serie,ostream,seperator=",",commend_tag="#"):
631             dsc="write %s to %s"%(time_serie,ostream)
632             dbg=time_serie.debug()
633             cntrl=time_serie.getControler()
634             self.__ostream=ostream
635             self.__seperator=seperator
636             TimeSeriesOperator.__init__(self,cntrl,[time_serie],0,0,dbg,dsc)
637             ostream.writelines("%s time series %s\n"%(commend_tag,str(self)))
638    
639  class TimeSeriesCollector(TimeSeries):        def update(self,start,end):
640        """TimeSeriesCollector collects values at time nodes"""           cntrl=self.getControler()
641        def __init__(self):           arg=self.getArguments(0)
642           TimeSeries.__init__(self)           n=arg.getNumComponents()
643             if n<2:
644        def __str__(self):              for i in range(start,end): self.__ostream.writelines("%s%s%s\n"%(cntrl[i],self.__seperator,arg[i]))
645           return "TimeSeriesCollector"           else:
646                for i in range(start,end):
647        def add(self,time_mark,value):                 l="%s"%cntrl[i]
648             """adds the value at time time_mark to the time series"""                 for j in range(n): l=l+"%s%s"(self.__seperator,arg[i][j])
649             self.append(numarray.array([time_mark]),numarray.array([value]))                 self.__ostream.writelines("%s\n"%l)
650    
651        def read(self,istream,seperator=","):  class DataCatcher(TimeSeries):
652          """reads pairs from iostream istream"""        """collects data into a time series."""
653          for l in istream:        def __init__(self,controler,numComponents=1,description="DataCatcher"):
654             d=l.strip().split(seperator)           self.__controler=controler
655             self.add(float(d[0]),float(d[1]))           dbg=controler.debug()
656             TimeSeries.__init__(self,TimeSeriesBaseBuffer(controler.getBaseBufferSize(),numComponents,DEFAULT_FLOAT_TYPE,controler.getIdOfFirstDatum(),dbg,"buffer for "+description),dbg,description)
657  class TimeSeriesIntegrator(TimeSeries,TimeSeriesFilter):  
658        def __init__(self,time_series):        def getControler(self):
659           TimeSeriesFilter.__init__(self,1)            return self.__controler
660           TimeSeries.__init__(self,buffer_size=time_series.getBufferSize(),cache_size=time_series.getCacheSize(), \  
661                                                                           numComponents=time_series.getNumComponents())        def nextValue(self,value):
662           self.setDebug(time_series.debug())            """append a value to the time series"""
663           time_series.checkInUpdate(self)            id_last=self.getIdOfLastDatum()
664           self.__integral=0            id_current=self.getControler().getIdOfLastDatum()
665              if id_last+1==id_current:
666        def __str__(self):               self.getDataset().append(value)
667           return "TimeSeriesIntegrator"            elif id_last+1<id_current:
668                   if self.isEmpty():
669        def update(self,times,values):                     self.getDataset().append(value)
670            l=times.shape[0]                     id_last+=1
671            self.append(times[1:l],(values[0:l-1]+values[1:l])/2.*(times[1:l]-times[0:l-1]))                 t_last=self.getControler()[id_last]
672                   t_current=self.getControler()[id_current]
673                   value_last=self[id_last]
674                   out=(value_last-value)/(t_last-t_current)*(self.getControler()[id_last+1:id_current+1]-t_current)+value
675                   self.getDataset().append(out)
676              else :
677                 raise ValueError,"%s: a new time node must be introduced before a new value can be added."
678              self.updateIdOfLastUnreferencedDatum(id_last)
679              
680      
681    class TimeSeriesCumulativeSum(TimeSeriesFilter):
682          """cummulative sum of the time series values"""
683          def __init__(self,time_serie):
684             dsc="cumsum(%s)"%(time_serie)
685             dbg=time_serie.debug()
686             cntrl=time_serie.getControler()
687             id_first_datum=time_serie.getIdOfFirstDatum()
688             TimeSeriesFilter.__init__(self,cntrl, \
689                         TimeSeriesBaseBuffer(cntrl.getBaseBufferSize(),time_serie.getNumComponents(),DEFAULT_FLOAT_TYPE,id_first_datum,dbg,"buffer for "+dsc), \
690                         [time_serie],0,0,dbg,dsc)
691             self.__last_value=0
692    
693          def update(self,start,end):
694              out=numarray.cumsum(self.getArgumentDataset(0)[start:end])+self.__last_value
695              self.__last_value=out[end-start-1]
696              self.append(out)
697                    
698    
699  class TimeSeriesDifferential(TimeSeries,TimeSeriesFilter):  class Reader(TimeSeriesBase):
700        def __init__(self,time_series):        """reads a list of input streams and creates a time series for each input stream but on the same Controler where the first column
701           TimeSeriesFilter.__init__(self,1)           is used to create the time nodes"""
702           TimeSeries.__init__(self,buffer_size=time_series.getBufferSize(),cache_size=time_series.getCacheSize(), \        def __init__(self,list_of_istreams,buffer_size=DEFAULT_BUFFER_SIZE,seperator=",",commend_tag="#",debug=False):
703                                                                           numComponents=time_series.getNumComponents())           TimeSeriesBase.__init__(self,debug=debug,description="reader")
704           self.setDebug(time_series.debug())           if not isinstance(list_of_istreams,list):
705           time_series.checkInUpdate(self)                self.__list_of_istreams=[list_of_istreams]
706             else:
707        def __str__(self):                self.__list_of_istreams=list_of_istreams
708           return "TimeSeriesDifferential"           self.__cntrl=Controler(buffer_size,debug,"reader controler")
   
       def update(self,times,values):  
           l=times.shape[0]  
           self.append((times[0:l-1]+times[1:l])/2,(values[0:l-1]-values[1:l])/(times[0:l-1]-times[1:l]))  
   
 class TimeSeriesViewer(TimeSeriesFilter):  
       def __init__(self,time_series):  
          TimeSeriesFilter.__init__(self,0)  
          time_series.checkInUpdate(self)  
   
       def __str__(self):  
          return "TimeSeriesViewer"  
   
       def update(self,times,values):  
           for i in range(times.shape[0]): print "[%s: %s]"%(times[i],values[i])  
   
 class TimeSeriesWriter(TimeSeriesFilter):  
       def __init__(self,time_series,ostream,seperator=","):  
          TimeSeriesFilter.__init__(self,0)  
          time_series.checkInUpdate(self)  
          self.setDebug(time_series.debug())  
          self.__ostream=ostream  
709           self.__seperator=seperator           self.__seperator=seperator
710             self.__commend_tag=commend_tag
711             self.__time_series={}
712             self.__t={}
713             self.__v={}
714             # set up the time series:
715             for i in self.__list_of_istreams:
716               line=self.__commend_tag
717               while  not line=="" and line[0]==self.__commend_tag:
718                   line=i.readline().strip()
719               if line=="":
720                  list_of_istreams.remove(i)
721               else:
722                  d=line.split(self.__seperator)
723                  self.__t[i]=float(d[0])
724                  tmp=[]
725                  for j in d[1:]: tmp.append(float(j))
726                  self.__v[i]=numarray.array(tmp)
727                  self.__time_series[i]=DataCatcher(self.__cntrl,len(d)-1,str(i))
728    
729             #
730          def run(self):
731             while len(self.__list_of_istreams)>0:
732                if len(self.__time_series)>0:
733                   # find list all times with minumum time node:
734                   tminargs=[]
735                   for i in self.__time_series:
736                       if len(tminargs)==0:
737                           tminargs.append(i)
738                       elif abs(t[tminargs[0]]-self.__t[i])<1.e-8*abs(self.__t[i]):
739                           tminargs.append(i)
740                       elif self.__t[i]<t[tminargs[0]]:
741                           tminargs=[i]
742                   # find list all times with minumum time node:
743                   self.__cntrl.nextTime(self.__t[tminargs[0]])
744                   for i in tminargs:
745                       self.__time_series[i].nextValue(self.__v[i])
746                       # find next line without leading "#"
747                       line="#"
748                       while not line=="" and line[0]==self.__commend_tag:
749                           line=i.readline().strip()
750                       # if eof reached iostream is removed for searching
751                       if line=="":
752                          self.__list_of_istreams.remove(i)
753                       else:
754                          d=line.split(self.__seperator)
755                          self.__t[i]=float(d[0])
756                          tmp=[]
757                          for j in d[1:]: tmp.append(float(j))
758                          self.__v[i]=numarray.array(tmp)
759    
760          def getControler(self):
761             """returns the controler shared by all time series created through the input streams"""
762             return self.__cntrl
763    
764          def getTimeSeries(self,istream=None):
765             """returns the time series as a tuple. If istream is present its time series is returned"""
766             if istream==None:
767                out=self.__time_series.values()
768                if len(out)>1:
769                   return tuple(out)
770                elif len(out)>0:
771                   return out[0]
772                else:
773                   return None
774             else:
775                return self.__time_series[istream]
776    
777    
778    class Plotter(TimeSeriesOperator):
779        def __init__(self,time_series,window_size=DEFAULT_BUFFER_SIZE/4,file_name=None,format=None):
780             if isinstance(time_series,list):
781                 dbg=time_series[0].getControler().debug()
782                 text=""
783                 for i in time_series:
784                   if len(text)==0:
785                      text=str(i)
786                   else:
787                      text=text+","+str(i)
788                 TimeSeriesOperator.__init__(self,time_series[0].getControler(),time_series,window_size,0,dbg,"plot(%s)"%text)
789             else:
790                 dbg=time_series.getControler().debug()
791                 text=str(time_series)
792                 TimeSeriesOperator.__init__(self,time_series.getControler(),[time_series],window_size,0,dbg,"plot(%s)"%text)
793             from pyvisi.renderers.gnuplot import LinePlot,Scene,PsImage
794             self.__renderer=Scene()
795             self.__line_plot=LinePlot(self.__renderer)
796             self.__line_plot.setTitle(text)
797             self.__line_plot.setLineStyle("lines")
798             self.__line_plot.setXLabel("time")
799             self.__line_plot.setYLabel("values")
800             self.__file_name=file_name
801             if format==None:
802                 self.__format=PsImage()
803             else:
804                 self.__format=format
805             self.__window_size=window_size
806    
807        def update(self,start,end):
808             s=max(end-self.__window_size,self.getControler().getIdOfFirstAvailableDatum())
809             args=[self.getControler()[s:end]]
810             for arg in self.getArguments(): args.append(arg[s:end])
811             self.__line_plot.setData(*args)
812             self.__line_plot.render()
813             if self.__file_name==None:
814                 raise SystemError,"Online viewing is not avilabel yet!"
815             else:
816                 self.__renderer.save(fname=self.__file_name, format=self.__format)
817                
818    
819    def viewer(time_serie,seperator=","):
820          """creates a viewer for a time series"""
821          import sys
822          return Writer(time_serie,sys.stdout,seperator)
823    
824        def __str__(self):  def differential(time_serie):
825           return "TimeSeriesWriter"        """calculates the derivative Dv of the time series v:
826            
827                Dv[n]=(v[n]-v[n-1])/(t[n]-t[n-1])
828    
829        def update(self,times,values):        """
830          for i in range(times.shape[0]): self.__ostream.writelines("%s,%s\n"%(times[i],values[i]))        out=(((time_serie<<1)-time_serie)/((time_serie.getControler()<<1)-time_serie.getControler())+ \
831               ((time_serie>>1)-time_serie)/((time_serie.getControler()>>1)-time_serie.getControler()))/2.
832          out.setDescription("d(%s)/dt"%str(time_serie))
833          out.setDebug(time_serie.debug())
834          return out
835    
836    def integral(time_serie):
837          """calculates the intagral Iv of the time series v using the trapozidal rule:
838            
839                Iv[n]=int_{t_0}^{t_n} v ~ sum_{0<i<=n} n (v[i]+v[i-1])/2*(t[i]-t[i-1])
840    
841          """
842          out=TimeSeriesCumulativeSum(((time_serie>>1)+time_serie)/2.*(time_serie.getControler()-(time_serie.getControler()>>1)))
843          out.setDescription("I (%s) dt"%str(time_serie))
844          out.setDebug(time_serie.debug())
845          return out
846    
847    def smooth(time_serie,range=5):
848         """smoothes a time series using the at each time the previous and next range values"""
849         i=integral(time_serie)
850         out=((i>>range)-(i<<range))/((time_serie.getControler()>>range)-(time_serie.getControler()<<range))
851         out.setDescription("smooth(%s,-%d:%d) dt"%(str(time_serie),range,range))
852         out.setDebug(time_serie.debug())
853         return out
854    
855    def leakySmooth(time_serie,l=0.99):
856         """leaky smoother: s(t)=int_{t_0}^{t} v(r) l^{t-r} dr/ int_{t_0}^{t} l^{t-r} dr """
857         w=l**(-time_serie.getControler())
858         out=integrate(time_serie*w)/integrate(w)
859         out.setDescription("leaky smoother(%s)"%str(time_serie))
860         return out
861    
862  # test  # test
863    
864  if __name__=="__main__":  if __name__=="__main__":
865       # tests the interfaces to data sets:
866       print "Test of Datasets:"
867       print "================="
868       bf=TimeSeriesBaseBuffer(buffer_size=5,numComponents=1,debug=True,description="TestBaseBuffer")
869       bfv_l=TimeSeriesBaseDataset(bf,offset=1,debug=True,description="offset 1")
870       bfv_r=TimeSeriesBaseDataset(bf,offset=-1,debug=True,description="offset -1")
871       bf.append([1.,2.,3.,4.])
872       print "should be all 2. :",bfv_l[0]
873       print bf[1]
874       print bfv_r[2]
875       bf.append([5.,6.,7.])
876       print "should be all 5. :",bfv_l[3],bf[4],bfv_r[5]
877       print "should be all 6. :",bfv_l[4],bf[5],bfv_r[6]
878       print "should be all 7. :",bfv_l[5],bf[6],bfv_r[7]
879       print "should be all [6., 7.] :",bfv_l[4:6],bf[5:7],bfv_r[6:8]
880    
881       print "Test of Controler"
882       print "================="
883       b=Controler(buffer_size=15,debug=True)
884       s3=b>>3
885       s1=b>>1
886       s_3=b<<3
887       print s_3
888       print b
889       print b+s3
890       sum=(s_3+b)+(b+s3)
891      
892       for i in range(30):
893           b.nextTime(i*1.)
894       b.flush()
895       print "should be all 28. :",s_3.getDataset()[25],b.getDataset()[28],s3.getDataset()[31]
896       print "should be all 29. :",s_3.getDataset()[26],b.getDataset()[29],s3.getDataset()[32]
897       print "should be all 96. :",sum.getDataset()[24]
898      
899       print "Test of operators"
900       print "================="
901       b=Controler(buffer_size=15,debug=True)
902       b.setFlushRate(2)
903       q=DataCatcher(b)
904       b1=b<<1
905       a=b+b1
906       a_s=b1+1.
907       s_a=1.+b1
908       d=b-b1
909       d_s=b1-1.
910       s_d=1.-b1
911       m=b*b1
912       m_s=b1*2.
913       s_m=2.*b1
914       dv=b/b1
915       dv_s=b1/2.
916       s_dv=2./b1
917       p=b**b1
918       p_s=b1**2.
919       s_p=2.**b1
920       pb=+b
921       mb=-b
922       sum=TimeSeriesCumulativeSum(b)
923       diff=differential(b)
924       smt=smooth(b,2)
925       int=integral(b*2)
926       fl=file("/tmp/test.csv","w")
927       w=Writer(q,fl)
928       v=viewer(q)
929       plo=Plotter([a,a_s],window_size=4,file_name="s.ps")
930       for i in range(30):
931           b.nextTime(i*1.)
932           if i%2==1: q.nextValue(i*28.)
933       b.flush()
934       print "a[28] should be %e: %e"%(28.+29.,a[28])
935       print "a_s[28] should be %e: %e"%(29.+1.,a_s[28])
936       print "s_a[28] should be %e: %e"%(29.+1.,s_a[28])
937       print "d[28] should be %e: %e"%(28.-29.,d[28])
938       print "d_s[28] should %e: %e"%(29.-1.,d_s[28])
939       print "s_d[28] should %e: %e"%(1.-29.,s_d[28])
940       print "m[28] should be %e: %e"%(28.*29.,m[28])
941       print "m_s[28] should be %e: %e"%(29.*2.,m_s[28])
942       print "s_m[28] should be %e: %e"%(29.*2.,s_m[28])
943       print "dv[28] should be %e: %e"%(28./29.,dv[28])
944       print "dv_s[28] should be %e: %e"%(29./2.,dv_s[28])
945       print "s_dv[28] should be %e: %e"%(2./29.,s_dv[28])
946       print "p[28] should be %e: %e"%(28.**29.,p[28])
947       print "p_s[28] should be %e: %e"%(29.**2,p_s[28])
948       print "s_p[28] should be %e: %e"%(2.**29.,s_p[28])
949       print "pb[28] should be %e: %e"%(28.,pb[28])
950       print "mb[28] should be %e: %e"%(-28.,mb[28])
951       print "sum[28] should be %e: %e"%(28*29./2,sum[28])
952       print "diff[28] should be %e: %e"%(1.,diff[28])
953       print "smt[27] should be %e: %e"%(27.,smt[27])
954       print "int[28] should be %e: %e"%(28.**2,int[28])
955       print "q[27] should be %e: %e"%(27*28.,q[27])
956       print "q[28] should be %e: %e"%(28*28.,q[28])
957       print "q[29] should be %e: %e"%(29*28.,q[29])
958       fl.flush()
959      
960       rin=Reader(file("/tmp/test.csv","r+"),buffer_size=15,debug=True)
961       rin.run()
962       inp=rin.getTimeSeries()
963       print "inp[27] should be %e: %e"%(27*28.,inp[27])
964       print "inp[28] should be %e: %e"%(28*28.,inp[28])
965       print "inp[29] should be %e: %e"%(29*28.,inp[29])
966    
    c=TimeSeriesCollector()  
    c.setDebugOn()  
    ii=TimeSeriesIntegrator(c)  
    d=TimeSeriesDifferential(c)  
    v=TimeSeriesViewer(ii)  
    w=TimeSeriesWriter(d,file("test.csv","w"))  
   
    for i in range(15):  
       c.add(i*1.,i+1.)  

Legend:
Removed from v.110  
changed lines
  Added in v.1387

  ViewVC Help
Powered by ViewVC 1.1.26