from numpy import *
from inner_hair_cell2018 import resting_potential, peak_potential

#parameters
r1=220 #reserve pool max. replenishment rate
x=700 #RRP replenishment rate (Pangrisc 2010,Chapocnikov 2014)
M=14 # Max. vesicles in the ready release pool or release sites (reasonable, ref?)
M2=60 # Max. vesicles in the second pool, fitted parameter
# with the paramaters is 250 release/s, because of refractoriness the steady state spike rate goes around 200 spike/s
refr_tail=0.6e-3 # relative refreactory period (from Peterson and Heil 2014)
abs_refractoriness=0.6e-3 # absolute refractory period (from Peterson and Heil 2014)
ss=1.5e-3 #sensitivity of release rate on IHC potential, fitted paramter
tCa=0.2e-3 #time constant of the Ca2 channel
#driven exocytosis rate is a boltzmann version of Vm, low-pass filter with the time constant of the Ca2+ channels. This is a shortcut to tune the nonlinear relationship between Vm and exocytosis rate based on AF data. Ca2+ signaling varies substantialy between synapses of the same IHC (Frank 2009,Ohn 2016). We use a shortcut Vm->Exocytosis rate, otherwise Vm->Ca2+ (at individual synapse)->exocytosis rate would require the tuning of too many parameters (here one free parameter ss, and 2 fitted parameters sp,psr)

def auditory_nerve_fiber(Vm,fs,spont):
    size=len(Vm[0,:])
    dt=1.0/fs
    if(spont==0):
        sp=1 #spont rate
        psr=800 #peak spike rate, based upon  Taberner and Liberman 2005
    elif(spont==1):
        sp=10.0
        psr=1.0e3
    else:
        sp=68.5
        psr=3.0e3
    #parameters for vesicles trafficking
#    psr=2.7e3
#    psr=psr*4;
    r=r1/M2 # replenishment rate per vesicle location
    M2_steady=M2-sp/r #steady state values
    Msteady=M*(M2_steady/M2-sp/x)
    wt=M2_steady+zeros([1,size]) #reserve pool
    qt=Msteady+zeros([1,size]) #RRP
    xdt=x*dt
    rdt=r*dt
    #parameters for refractoriness
    alpha_ref=exp(-dt/refr_tail)
    relRefFraction=zeros([1,size]) #how much the firing probability decreases due to relative refractoriness
    available=1.0+zeros([1,size]) #number of fibers not in a refractory state
    buf_lgt=int(round(abs_refractoriness*fs)) #length of buffer to store the firing history (in order to account for absolute refractoriness)
    buf_ref=zeros([buf_lgt,size],dtype=float) #buffer to store the history of firing
    buf_pointer=0
    pp=psr/Msteady#/(1/(1+exp(-(peak_potential-vh)/ss))) #multiplier relating the activation nonlinearity (between 0 and 1) with actual firing rate
    #parameters to relate Vm with firing rate
    rat=log((psr-sp)/sp) #find half activation voltage of exocytosis rate based on peak and spontaneous rate
    vh=rat*ss+resting_potential
    k0=sqrt(1/(1+exp(-(resting_potential-vh)/ss)))+zeros([1,size])  #driven exocytosis rate at rest
    #take the square root, filter it with a first order filter and then square it. This is equivalent to a second order activation of the ion channels
    alphaCa=exp(-dt/tCa)
 

    zero_time=int(50e-3*fs)
    for i in range(zero_time):
        vesicleReleaseRate=pp*(k0**2)
        releaseProb=vesicleReleaseRate*dt
        qt[qt>M]=M
        wt[wt>M2]=M2
        ejected=releaseProb*qt
        replenishReserve= rdt*(M2-wt)
        replenishRRP=xdt*fmax(wt/M2-qt/M,0)
        qt= qt + replenishRRP - ejected
        wt= wt - replenishRRP + replenishReserve
        firing=(available-relRefFraction)*ejected
        recovered=buf_ref[buf_pointer,:]
        relRefFraction=alpha_ref*relRefFraction+(1-alpha_ref)*recovered
        available=available-firing+recovered
        buf_ref[buf_pointer,:]=firing
        buf_pointer=mod(buf_pointer+1,buf_lgt)
    k=k0
    kin=sqrt(1/(1+exp(-(Vm-vh)/ss)))
    solution=zeros_like(Vm)
    for i in range(len(kin[:,0])):
        k=alphaCa*k+(1-alphaCa)*kin[i,:]
        vesicleReleaseRate=pp*(k**2)
        releaseProb=vesicleReleaseRate*dt
        qt[qt<0]=0
        wt[wt<0]=0
        qt[qt>M]=M
        wt[wt>M2]=M2
        ejected=releaseProb*qt
        replenishReserve= rdt*(M2-wt)
        replenishRRP=xdt*fmax(wt/M2-qt/M,0)
        qt= qt + replenishRRP - ejected
        wt= wt - replenishRRP + replenishReserve
        firing=(available-relRefFraction)*ejected
        recovered=buf_ref[buf_pointer,:]
        relRefFraction=alpha_ref*relRefFraction+(1-alpha_ref)*recovered
        available=available-firing+recovered
        buf_ref[buf_pointer,:]=firing
        buf_pointer=mod(buf_pointer+1,buf_lgt)
        solution[i,:]=firing
    return solution