delays

# delays.py
# ------------------------------------------------------------------------------

 
Classes
       
ExpDelay
StepDelay

 
class ExpDelay()
    Class used to create exponential delays in systems of ODEs in continuous 
simulations.
    An exponential delay is characterized by tau*(dy1/dt) + y1 = y0; 1st 
order, and 2nd order is provided by the above and tau*(dy2/dt) + y2 = y1; 
etc etc.....  The class can be used for ODEs formulated using dictionaries 
as well as lists/stacks. 
 
The order of the delay is implied in the list input vector of the delay (the 
number of elements of the state dictionary or list/stack that is included in
the keys or indices is one more than the order: three elements implies 2nd 
order, etc). state is the FULL present state dictionary or list/stack.
 
An example of how it should be used for dictionaries (assumes deriv is a 
dict):
    id = ExpDelay(['id0', 'id1','id2'], 0.50, 2.5) # Initiate instance obj.
    # Implies 2nd order and a response time of 2.5 to reach 50 % of a step 
    # input height.
    # And for each time step:
    deriv['id0']  = somethingwithoutdelay           # ..or what have you..  
    deriv['id1'], yDeriv['id2']  = id.delay(state)  # Compute for daughters
    somethingafterdelay  = deriv['id2']             # Finally after delay
 
and for stacks (assuming that the indices of the elements in the state 
vector involved in the delay are 7, 8 and 9):
    id  = ExpDelay([7, 8, 9], 0.50, 2.5)     # The rest as above
    # And for each time step (deriv = Stack() must be set for each step):
    deriv.push(somethingwithoutdelay)        # or what have you...
    deriv.push(id.delay(state))  # compute for daughters and append to stack
    somethingafterdelay  = deriv[-1]         # finally after delay
 
If a list is used instead of a stack for yDeriv the whole thing gets a bit 
more complicated since the indices must be kept track of in each time step -
using stacks allows you to just use the 'push' method of the Stack class. 
 
The advantage of using dicts is - besides more clarity due to the 
possibility of using strings rather than indices to identify the 
elements of the derivatives vector and the state vector - is that 
the order in which the different elements of the vectors are treated in 
the function called by the methods in ODEsSolution is not crucial!
 
The rate constant object.lam = 1.0/tau is also available to the caller.
 
  Methods defined here:
__init__(self, sequence, fraction, time_to)
Inputs to the class are the list or tuple containing the keys or range 
associated with the state variables involved in the specific delay 
(that also determines the order of the delay). 
 
The characteristic time (time constant) of the delay is computed for 
later use: if "fraction" is the string 'peak' the time constant for 
an exponential delay of the present order for the time "time_to" for 
the response to a delta (spike/pulse/Dirac) input to reach its peak. 
For "fraction" in [0.0, 1.0] "time_to" is used to compute the time 
constant for the response to a step input to reach the given fraction 
of the step height. (The time to the peak and the time to a certain 
fraction are referred to as "time to rise point" in the error messaging)
delay(self, state)
The method used to compute the list of values for the derivatives of the 
elements involved in a specific delay. A list is returned which must be 
used to fill the full derivatives dict, stack or list involved in the 
solution of the ODE at hand.
 
The function takes the full present state vector (a dict, a stack or 
a list) as its sole input.

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
class StepDelay(builtins.object)
    Class primarily designed to handle step delays in systems of ODEs in 
continuous simulations, but it may be used for other computational purposes 
as well. An step delay is characterized by y1(t) = y0(t-tau) where tau is 
the time delay, and where y may be state variables OR derivatives OR 
anything. The class may be used with dicts or with lists/stacks. 
 
The following is an example of how it could be used (delay between 
y['ident1'] and y['ident2'] in the dict formulation, or between y[1] 
and y[2] in the list formulation):
    from delays import StepDelay
    y           = {}
    y['ident0'] = 0.0
    y['ident1'] = 0.0
    y['ident2'] = 0.0
    sequence    = ('ident1', 'ident2')
    tdelay      = 2.0
    one_two     = StepDelay(sequence, tdelay)
    for k in range(0, 100):
        t           = float(k)
        y['ident0'] = anything
        y['ident1'] = exp(t)
        y['ident2'] = one_two.delay(y, t)
 
with a dict, and 
 
    from delays import StepDelay
    y        = [0.0, 0.0, 0.0]
    sequence = (1, 2)
    tdelay   = 2.0
    one_two  = StepDelay(sequence, tdelay)
    for k in range(0, 100):
        t    = float(k)
        y[0] = anything
        y[1] = exp(t)
        y[2] = one_two.delay(y, t)
 
with a list.
 
  Methods defined here:
__init__(self, sequence, tdelay)
Initiates the object with the "parent-daughter" sequence involved in 
the delay and the delay time.
delay(self, y, time)
Creates the delay between the two members of the sequence given the full 
state vector (dict/list/stack) and the time. The function uses linear 
interpolation in the parent's temporal history to come up with the value 
for the "daughter".

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Functions
       
bisect(...)
Alias for bisect_right().
exp(...)
exp(x)
 
Return e raised to the power of x.